I decided to write ES6 class for Express server, but extended Express overrides child prototype, and there is no way to use methods and props that defined outside constructor. See code:
import Express from 'express'
export default class Server extends Express {
constructor(options) {
super(options.expressOptions || {})
super.use(cookieParser()) // TypeError: (intermediate value).use is not a function
this.use(bodyParser.json()) // This definition works cause of overridden prototype
this.use(Express.static('static'))
this.test() // TypeError: this.test is not a function
this.test1 = '123' // Contains in Server final prototype
}
test() {
console.log('test')
}
}
And problem with super class definition. I don't know how to save child prototype. It's will be very precious if you help.
Having looked again at this, I see the problem.
express is not a constructor.
You are treating express as if it were a constructor that you call using new Express. This is not how it works: you just call it with, for example, const app = express(). In fact, express is a function (here's the source code) that creates the object for you, in an old-fashioned (non-ES6) way.
As far as I am aware, it is not possible to subclass any of the core Express objects. You could, I guess, use classes to wrap the Express framework objects, but that doesn't seem intuitive to me.
Related
I am using a javascript library that constructs an object like so:
usefulJS.js
function usefulJS() {}
usefulJS.protoype.doAThing = function() {
//does a thing here, returns an object
};
module.exports = new usefulJS();
It has a type definition file like so:
usefulJS/index.d.ts
export class usefulJS {
public doAThing(): object;
}
And it is used in the following typescript file:
myTypescript.ts
import {randomOtherThing,usefulJS} from "library-that-includes-usefulJS";
const myObj = usefulJS.doAThing();
But I get a red underline under .doAThing() in my typescript file with the following message:
"Property 'doAThing' does not exist on type 'typeof usefulJS'."
When I run the code with //#ts-ignore over the function call it works, so it definitely seem to be a typescript issue and not a javascript issue.
Am I doing something wrong with my imports? How should I import an object that is already constructed, as opposed to a prototype for an object?
Or is there something wrong with the library's type definitions?
If it is any help, there is another project in non-typescript node that uses this library. Its import line looks like this:
const usefulJS = requre("library-that-includes-usefulJS").usefulJS;
Just a guess: TypeScript probably locate usefulJS from usefulJS.js instead of index.d.ts (you can check if that's the case by using "go to definition" in VS Code). If that's the case TypeScript will not recognize that usefulJS has a doAThing method, because it is assigned through prototype. You can probably solve this by adding this to your tsconfig.json:
"compilerOptions": {
"baseUrl": "./",
"paths": {
"library-that-includes-usefulJS": [
"./usefulJS/index.d.ts"
]
}
}
By making library changes I am able to get it to work.
Basically, the index.d.ts file doesn't indicate that helpfulJS.js exports a value. Unfortunately, we can't indicate that it exports the value helpfulJS, because that would result in a name overlap with the type. So helpfulJS.js needs to be modified to export a different variable name.
usefulJS.js
function usefulJS() {}
usefulJS.protoype.doAThing = function() {
//does a thing here, returns an object
};
let usefulJSObj = new usefulJS();
module.exports = usefulJSObj;
usefulJS/index.d.ts
export class usefulJS {
public doAThing(): object;
}
export const usefulJSObj : usefulJS;
myTypescript.ts
import {randomOtherThing,usefulJSObj} from "library-that-includes-usefulJS";
const myObj = usefulJSObj.doAThing();
I do have the ability to change this library in this case but I am loath to do so because it has impact on other projects.
I am still hoping there is a way to fix this without changing the library (or maybe only changing the type file, since the other users of the library are javascript).
I found a way to change the library that solves the problem without making any of the existing javascript clients change their code.
Basically, by changing the library to export a type with static functions instead of an unnamed object with object functions, typescript stops complaining about being unable to call the method and the javascript calls to the library don't change at all.
(usefulJS.doAThing() with usefulJS as an object calling its prototype function changes to usefulJS.doAThing() as a type calling its static function, with javascript not caring about the difference.)
usefulJS.js
class usefulJS() {
static doAThing() {
//does a thing here, returns an object
};
}
//Returns a type with a static method instead of a constructed object
module.exports = usefulJS;
usefulJS/index.d.ts
export class usefulJS {
public static doAThing(): object;
}
myTypescript.ts
import {randomOtherThing,usefulJS} from "library-that-includes-usefulJS";
const myObj = usefulJS.doAThing();
Still doesn't help much for those who don't have control over the library, unfortunately, but at least we don't cause exploding changes to all the javascript clients that already worked just to make typescript clients work.
I have recently discovered Meteor and I am struggling with using ES6 classes and imports in a new Meteor project. What I want to do is to have a complex structure of classes, which methods get called from Meteor events/methods/helpers. I've added Babel.js to the project by writing a command $ meteor add grigio:babel and it works properly.
Example of what I am trying to achieve:
in server/models/article.js:
class Article {
static all() {
//returns all articles from db
}
}
in server/methods/articles.js:
Meteor.methods({
allArticles: {
Article.all();
}
})
Having just that raises ReferenceError: Article is not defined in a methods file, which is adequate. So I have got three options: write all classes in one file, append all classes to a global object or use a good module system like Browserify. Obviously, third option is better.
But how do I use that? Babel converts export, import into Browserify by default and Meteor raises a require is not defined error on page refresh. After googling the problem I didn't find a clear solution on how to add Browserify to Meteor. Should I add a npm packages support to Meteor, add a npm package of browserify and add it manually to Meteor on every page where I import/export anything? Or should I use a completely different approach? How is this task usually handled in Meteor? Thank you!
I was reading about this earlier and found this issue on github that may help.
Essentially just assign the class to a variable that is exposed to both the client and server (lib/both/etc depends on your file structure). Like so:
Article = class Article {...}
Seems to be the best solution at the moment.
The way I do this is to collect objects together into various namespaces, for example:
// Global
Collections = {};
class Article {
static all() {
//returns all articles from db
}
}
_.extend(Collections, { Article });
Then to avoid having to use Collections.Article everywhere I can use the following in the file I need to access Article in:
// Make `Article` available
let { Article } = Collections;
I am using Meteor 1.4.1.1 and the error remains, when reproducing your approach. However, there are some new ways to use es6 classes now:
1. Export your class as a constant (e.g. for use as a singleton object):
class MyModuleInternalClassName {
//... class internals
}
export const PublicClassName = new MyModuleInternalClassName();
You can import this one via
import {PublicClassName} from 'path/to/PublicClassFileName.js';
2. Export your class directly as the module's default
export default class PublicClassName {
//... class internals
}
and then import it (as with the above one) as the following
import {PublicClassName} from from 'path/to/PublicClassFileName.js';
let myInstance = new PublicClassName();
+++++++++++++++++++++++++++++++++
Regarding the question of OP and the error, you can try something like this:
Article.js
class InternalArticle {
constructor(){
//setup class
}
all() {
//returns all articles from db
}
register(article){
//add article to db
}
}
export const Article = new InternalArticle();
Import and use the Singleton
import {Article} from 'path/to/Article.js';
//either register some article
Article.register(someArticle);
//or get all your articles
const allArticles = Article.all();
In a new ember App you write first:
var App = Ember.Application.create({
test: 'foo',
...
});
In a new ember-cli App you write first:
var App = Ember.Application.extend({
test: 'foo',
...
});
Why?
( In the second case, I can't read a global property (App.test) from a controller. !? )
This question actually has a lot to do with Ember.Object.
.extend() creates a new class that extends the old one, with class-level properties defined in the hash that is passed in.
.create() create a new instance of the class, with object-level properties defined in the hash that is passed in.
This is why you cannot read the property in the second case. If you want to do that, you will need to do:
var App = Ember.Application.extend({});
App.test = 'foo';
In a plain Ember app, you can create an instance of the App object, because you are going to use it directly.
In an ember-cli generated Ember app, you do not create an instance of the App object, you merely define its class (using .extend()). This is because you do not use it directly, as ember-cli wants the class, so that it may do its own things to it, before it internally instantiates it.
I've got some CoffeeScript classes which I use and extend in my code. How can I use angularjs to not have to create the usual module cruft like
MyNamespace = MyNamespace || {}
MyNamespace.SuperClass = class
and in a different file
MyNamespace = MyNamespace || {}
class ChildClass extends MyNamespace.SuperClass
MyNamespace.ChildClass = ChildClass
Could I simply write
angular('MyModule').factory, 'SuperClass', () ->
class SuperClass
constructor: (#id) ->
return SuperClass
and extend from that class via
angular('MyModule').factory, 'ChildClass', ['SuperClass', (SuperClass) ->
class ChildClass extends SuperClass
constructor: (id) ->
super(id)
return ChildClass
]
My problem is actually that Im using CoffeeScript to compile all objects into a single file. Now if a childclass is above the baseclass, the baseclass will be undefined and I'll get an error. I'm looking for an elegant and easy way how to solve this.
If you use Angular's DI system, it should ensure that your classes are instantiated in the correct order, regardless of which is loaded first. Is there actually an issue with your example?
With Angular you can do away with putting your classes in namespaces, since the name of your module / service can be qualified and effectively serve the same purpose.
What I don't think Angular will help with is ensuring that your super class code is run before your child class code. For that there seems to be about 8000 ways of solving the problem and none of them standard - requireJs, coffeetoaster, brunch, grunt, cake.....
I use grunt, and specify the order in which I want to concat my coffeescript.
I am new to Javascript and am seeing a lot of usage of exports and prototype in the code that I read. What are they mainly used for and how do they work?
//from express
var Server = exports = module.exports = function HTTPSServer(options, middleware){
connect.HTTPSServer.call(this, options, []);
this.init(middleware);
};
Server.prototype.__proto__ = connect.HTTPSServer.prototype;
Exports is used to make parts of your module available to scripts outside the module. So when someone uses require like below in another script:
var sys = require("sys");
They can access any functions or properties you put in module.exports
The easiest way to understand prototype in your example is that Server is a class that inherits all of the methods of HTTPSServer. prototype is one way to achieve class inheritance in javascript.
This video explains node.js module.exports and here is a resource which describes JavaScript prototype.