Inheritance TypeScript with exported class and modules - node.js

I'm getting crazy with inheritance using typescript. I don't know why but it cannot resolve the class I want to inherit.
lib/classes/Message.class.ts
///<reference path='./def/lib.d.ts'/>
///<reference path='./def/node.d.ts'/>
export module SharedCommunication {
export class Message{
// Stuff
}
}
lib/classes/ValidatorMessage.class.ts
///<reference path='./def/lib.d.ts'/>
///<reference path='./def/node.d.ts'/>
///<reference path='Message.class.ts'/>
export module SharedCommunication {
export class ValidatorMessage extends Message{
private _errors;
}
}
Message cannot be resolved. I tried SharedCommunication.Message too but it's the same. I reference the class so I don't understand at all what's going on. Do you have any idea?
I tried without the module (two class without be in any module) but it's the same. I need to export the class (and the module if I use it) to get them from another node_module: typescript.api, which I use to load the class and use it in node.
lib/message.js
var Message = require('./classes/Message.class.ts');
module.exports = Message.SharedCommunication.Message;
What's the trick here? Because I have source code on the same project in a different folder working with inheritance, without module or export. Thanks.

ValidatorMessage.class.ts should look like this:
///<reference path='./def/lib.d.ts'/>
///<reference path='./def/node.d.ts'/>
import message = require('./Message.class');
export module SharedCommunication {
export class ValidatorMessage extends message.SharedCommunication.Message {
private _errors;
}
}
It's usually redundant to have a single export module at the top level of a file since the file itself constitutes a namespace anyway.
Bill mentioned this in your other question, but I'd again caution on using RequireTS if you're just starting out with TypeScript - it sounds pretty unmature and is likely to introduce a lot of confusion.

Take out the export from the mododule declaration:
module SharedCommunication
{
export class ValidatorMessage extends message.SharedCommunication.Message
{
private _errors;
}
}

Related

Compiler error on using namespace's parameterized constructor of a class

I want to initialize a class present in Typescript's namespace. This class has a parameterized constructor, but when I tried to use this class then compiler complains about it and I cannot use this class for instantiation.
**Inside file tv.dto.ts**
export namespace tv{
export class Trial{
private name:string;
Trial(name:string){
this.name=name;
}}}
Inside my other Jest class file.
import { tv } from "./tv.dto";
import {Graph} from 'graphlib';
describe('testing',()=>{
it('TestCase1',() =>{
let k=new tv.Trial("WonderFulName");// It flags compiler error here.
console.log(JSON.stringify(k));
});
});
Error message which I received was "TS2554: Expected 0 arguments, but got 1."
Screenshot for the same.
Please help me in resolving this issue.
Edit:
I am able to resolve this issue by importing properly:
import {tv as tv} as './tv.dto'
Don't export the namespace, instead just keep the export of Trial. Then import that instead from the same file reference.
Edit: Alternatively, change the constructor to use the word "constructor" instead of the class name.

Why am I getting a Reference error when I try to extend a class from an external class using JS

I have the following code...
class BasePage{
constructor(driver){
...
}
}
class Section extends BasePage{
constructor(driver, parent){
super(driver);
...
}
...
}
export {BasePage, Section}
This seems to work, however, when I try to move section into its own folder and file like this...
import {BasePage} from "../BasePage";
export class Section extends BasePage{
constructor(driver, parent){
super(driver);
}
}
I get an error...
(node:12480) UnhandledPromiseRejectionWarning: ReferenceError: BasePage is not defined
at file ... Section.mjs
This doesn't make any sense to me and if I take the extends off and try to instantiate it works fine...
export class Section{
constructor(driver, parent){
new BasePage(driver); // works fine
}
}
What is going on here? Why am I getting a BasePage not defined?
Update
Here is the whole code
You have a circular dependency.
index.mjs loads BasePage.mjs
BasePage.mjs loads Other.mjs before running export class BasePage {}
Other.mjs loads Section.mjs
Section.mjs skips BasePage.mjs because it already in-progress from step 2.
Section.mjs tries to run export class Section extends BasePage { /* ... */ }, which throws because export class BasePage {} from step 2 hasn't run yet.
You haven't shown why you need to import Other inside BasePage so it is hard to recommend changes, but essentially you'll want to not do that.

How to properly extend a class with TypeScript in NodeJS?

I want to use TypeScript in a NodeJS environment. Since I'm absolutely new to TypeScript I'm not sure how to extend classes properly with the NodeJS module system.
I want to extend my class Champion with GameObject.
GameObject.ts
///<reference path="../../typings/node/node.d.ts"/>
class GameObject {
id:number;
name:string;
}
module.exports = GameObject;
Champion.ts
///<reference path="../../typings/node/node.d.ts"/>
///<reference path="Image.ts"/>
///<reference path="GameObject.ts"/>
class Champion extends GameObject {
// ...
}
module.exports = Champion;
This throws no compilation error so far.
Now I want to create an instance of my Champion. This is what I've tried
// I tried referencing the Champion.ts which haven't changed anything
var Champion = require('../api/types/Champion');
var c = new Champion();
My Champion.js now throws the following error:
ReferenceError: GameObject is not defined
So I thought I need to require('GameObject') in Champion.ts which make my application running. But I get another error.
Either I reference and require my GameObject
///<reference path="GameObject.ts"/>
var GameObject = require('./GameObject');
class Champion extends GameObject {
Which gives me the error
Duplicate Identifier GameObject
Or I just require and get
Type any is not a constructor function type
TypeScript Version
$ tsc -v
message TS6029: Version 1.6.2
Instead of using module.exports = GameObject; with var/require use import/require
This will give you type safety on the import side. These are called file modules and documented here : https://basarat.gitbooks.io/typescript/content/docs/project/modules.html

What's the correct way to use requireJS with typescript?

The examples I have found here and here say to use module(). However, when I compile I get "warning TS7021: 'module(...)' is deprecated. Use 'require(...)' instead."
So a couple of basic questions:
When using typescript and requireJS, how do I access a class in one
.ts file from another .ts file where requireJS will load the second
file and give me the class in the first file?
Is there a way to do the standard requireJS approach with two .ts files where the define() at the top loads the second ts file and returns back the object it builds at the end?
Sort-of the same as question #2. From a java script file, can I use the define() construct on a type script file to get the instantiated object? If so, how?
Update: The following gives me a tsc compile error:
///<reference path='../../libs/ExtJS-4.2.0.d.ts' />
///<reference path='../../libs/require.d.ts' />
import fdm = require("./file-definitions");
require(["../../scripts/ribbon"], function () {
export module Menu {
export class MainMenu {
I would have commented on David's reply to basarat's answer (regarding modules and classes), but I don't have the reputation. I know this question is stale, but I didn't find an answer elsewhere.
I succeeded by using basarat's videos, combined with some other resources, to figure it out for classes like David Thielen needed. Note that I no longer have entries for my ts source files, but I do have amd-dependency and import statements. In Eclipse with palantir's TS plugin, my code completion and ability to jump from usage to definition is working with just the amd-dependency and import statements. The header files still need statements since they have nothing to do with deployment and are only used by the TS compiler. Note also that the .ts file extensions are used for reference statements but not the amd and import statements.
In Utils.ts I have:
///<reference path="headers/require.d.ts" />
export function getTime(){
var now = new Date();
return now.getHours()+":"+now.getMinutes()+':'+now.getSeconds();
}
In OntologyRenderScaler I have:
///<reference path="headers/require.d.ts" />
///<reference path="headers/d3.d.ts" />
///<reference path="headers/jquery.d.ts" />
///<amd-dependency path="Utils" />
import Utils = require('./Utils');
export class OntologyRenderScaler {
...
Utils.getTime();
...
}
In OntologyMappingOverview.ts I have:
///<reference path="headers/require.d.ts" />
///<reference path="headers/d3.d.ts" />
///<reference path="headers/jquery.d.ts" />
///<amd-dependency path="Utils" />
///<amd-dependency path="OntologyGraph" />
///<amd-dependency path="OntologyFilterSliders" />
///<amd-dependency path="FetchFromApi" />
///<amd-dependency path="OntologyRenderScaler" />
///<amd-dependency path="GraphView" />
///<amd-dependency path="JQueryExtension" />
import Utils = require('./Utils');
import OntologyGraph = require('./OntologyGraph');
import OntologyRenderScaler = require('./OntologyRenderScaler');
import OntologyFilterSliders = require('./OntologyFilterSliders');
import GraphView = require('./GraphView');
export class OntologyMappingOverview extends GraphView.BaseGraphView implements GraphView.GraphView {
ontologyGraph: OntologyGraph.OntologyGraph;
renderScaler: OntologyRenderScaler.OntologyRenderScaler;
filterSliders: OntologyFilterSliders.MappingRangeSliders;
...
this.renderScaler = new OntologyRenderScaler.OntologyRenderScaler(this.vis);
...
}
I didn't manage (yet!) to get things working like codeBelt suggested above, but an exchange we had on his blog revealed that if I get his approach working (with export MyClass at the bottom of the file), then I would not need to double up the imported identifer with the class name. I suppose it would export the class of interest rather than the namespace it is defined in (the implicit external module, i.e. the TypeScript file name).
For :
When using typescript and requireJS, how do I access a class in one
.ts file from another .ts file where requireJS will load the second
file and give me the class in the first file? Is there a way to do the
standard requireJS approach with two .ts files where the define() at
the top loads the second ts file and returns back the object it builds
at the end?
simply :
// from file a.ts
export class Foo{
}
// from file b.ts
// import
import aFile = require('a')
// use:
var bar = new aFile.Foo();
and compile both files with --module amd flag.
For :
Sort-of the same as question #2. From a java script file, can I use
the define() construct on a type script file to get the instantiated
object? If so, how?
To use a.ts from b.js simply :
// import as a dependency:
define(["require", "exports", 'a'], function(require, exports, aFile) {
// use:
var bar = new aFile.Foo();
});
This is similar to what you would get if you compile b.ts
You want the export statement below the class you are creating.
// Base.ts
class Base {
constructor() {
}
public createChildren():void {
}
}
export = Base;
Then to import and use into another class you would do:
// TestApp.ts
import Base = require("view/Base");
class TestApp extends Base {
private _title:string = 'TypeScript AMD Boilerplate';
constructor() {
super();
}
public createChildren():void {
}
}
export = TestApp;
I have been playing with typescript, trying to integrate it in our existing javascript/requirejs project.
As setup, I have Visual Studio 2013 with Typescript for vs v 0.9.1.1. Typescript is configured (in visual studio) to compile modules in amd format.
This is what I have found works for me (there might be a better way of course)
Use amd-dependency to tell the typescript compiler adds the required module to the list of components which must be loaded
In the constructor of the class being exported, use requirejs’s require function to actually fetch the imported module (at this point this is synchronous because of the previous step). To do this you must reference require.d.ts
As a side note, but since it is in my view essential to typescript, and because it gave me a bit of a headache, in the example I show two ways to export classes which use interfaces. The problem with interfaces is that they are used for type checking, but they produce no real output (the generated .js file is empty), and it causes problems of the type ‘’export of a private class”
I have found 2 ways of exporting classes which implement an interface:
Simply add an amd-dependency to the interface (as is in the Logger.ts file)
And export a typed variable holding a new instance of the class
The exported class can be consumed directly (ie myClass.log(‘hello’));
Don’t add the amd- dependency to the interface (as is in the Import.ts file)
And export a function (ie Instantiate()) which returns a variable of type any holding a new instance of the class
The exported class can be consumed via this function (ie myClass.instantiate().log(‘hello’))
It seems like the first option is better: you don’t need to call the instantiate function, plus you get a typed class to work with. The downside is that the [empty] interface javascript file does travel to the browser (but it’s cached there anyway, and maybe you are even using minification in which case this does not matter at all).
In the next blocks of code there are 2 typescript modules loaded with requires (amd): Logger and Import.
ILogger.ts file
interface ILogger {
log(what: string): void;
}
Logger.ts file
///<reference path="./ILogger.ts"/>
//this dependency required, otherwise compiler complaints of private type being exported
///<amd-dependency path="./ILogger"/>
class Logger implements ILogger {
formatOutput = function (text) {
return new Date() + '.' + new Date().getMilliseconds() + ': ' + text;
};
log = function (what) {
try {
window.console.log(this.formatOutput(what));
} catch (e) {
;
}
};
}
//this approach requires the amd-dependency above for the interafce
var exportLogger: ILogger = new Logger();
export = exportLogger;
Using Logger.ts in another ts file(Import.ts)
///<reference path="../../../ext/definitions/require.d.ts"/>
///<amd-dependency path="Shared/Logger"/>
///<amd-dependency path="./IImport"/>
class _Import implements IImport{
ko: any;
loggerClass: ILogger;
constructor() {
this.ko = require('knockout');//require coming from require.d.ts (in external_references.ts)
this.loggerClass = require('Shared/Logger');
}
init(vm: any) {
this.loggerClass.log('UMF import instantiated...');
}
}
////Alternative Approach:
////this approach does not require adding ///<amd-dependency path="./IImport"/>
////this can be consumed as <imported_module_name>.instantiate().init();
//export function instantiate() {
// var r : any = new _Import();// :any required to get around the private type export error
// return r;
//}
//this module can be consumed as <imported_module_name>.init();
var exported: IImport = new _Import();
export = exported;
IImport.ts file
interface IImport {
init(vm: any): void;
}
To consume the Import module straight from javascript use something like (sorry I have not tried this one, but it should work)
define (['Import'], function (import)
{
//approach 1
import.init();
////approach 2
//import.instantiate().init();
});

TypeScript module import in nodejs

What is best practice for importing modules in nodejs with typescript? I come from c# background so I want to do something like this
MyClass.ts
module MyNamespace {
export class MyClass {
}
}
app.ts
// something like using MyNamespace
new MyNamespace.MyClass();
or
MyClass.ts
export class MyClass {
}
app.ts
import MyClass = module("MyClass")
new MyClass();
I know I can do this and it will work, but then I have to think up for two names for each class
import MyClass2 = module("MyClass")
new MyClass2.MyClass();
Point is separating classes to multiple .ts files (preferably one file per class). So question is, how is this done?
You have two choices here:
If you insist on using CommonJS or AMD modules, then you will have to use external modules just the way you described it in your question. Whether or not you use a module to declare your own namespace is mostly a matter of taste. The only way to circumvent the issue of specifying two names is to create a variable that aliases the type:
mymodule.ts
export module MyNamespace {
export class MyClass {
}
}
app.ts
import ns = require('mymodule');
var myclass = new ns.MyNamespace.MyClass();
var myclassalias = ns.MyNamespace.MyClass;
var myclass2 = new myclassalias();
Your other option is to use internal modules which are mostly used to structure your code internally. Internal modules are brought into scope at compile time using reference paths.
mymodule.ts
module MyNamespace {
export class MyClass {
}
}
app.ts
///<reference path='mymodule.ts'/>
var myclass = new MyNamespace.MyClass();
I think you'll have to decide for yourself which of those two approaches is more appropriate.
You can import TypeScript modules into a node.js file using the typescript-require module, which was created for this specific purpose.
I would recommend against using the explicit module (or namespace) keyword, it's a vestigial remnant of an earlier time.* You generally don't need them because any typescript file with a top-level import or export is automatically a module. Your second myModule.ts example was good.
export class MyClass {
...
}
But when you import it to another typescript module, you'll want to use something like this:
import { MyClass } from './myModule';
var myInstance = new MyClass();
Personally, I don't like repetitiveness of line 1, but it is what the language calls for, so I've learned to accept it. I think the utility of this syntax isn't apparent unless you abandon the file-per-class pattern. You pick and choose what names to import from the module, so that no unintended namespace pollution occurs.
An alternative import syntax pulls in all names from the module, but you must qualify the names with the module when you use them. Therefore it is also name collision resistant.
import * as myModule from './myModule';
var myInstance = new myModule.MyClass();
There are exceptions to the general rule about not needing module / namespace keywords, but don't start by focusing on them. Think file == module.

Resources