Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How write declaration for class and namespace with same name in Typescript

Tags:

typescript

I'm using a 3rd party Javascript library in this format:

var MyClass = function (name) {
    this.name = name;
}

MyClass.prototype.greet = function () {
    window.alert('Hello ' + this.name)
}

I want to write a Typescript declaration for this. I've got this sort of thing:

declare class MyClass {
    constructor(name: string);
    greet(): void;
}

This is all compiling fine and when I just want to refer to the types it is working as expected. But I'm having problems trying to use the class implementation.

Using it this way, it compiles and runs, but I get no compile time checking

const MyClass = (require('./MyClass') as any).MyClass;
const a = new MyClass('Bob'); //a is any

Using it this way I get a compiler error

const MyClass = (require('./MyClass') as any).MyClass as MyClass;
const a = new MyClass('Bob'); //Cannot use 'new' with an expression whose type lacks a call or construct signature.

Using it this way I get a compiler error

import './MyClass';
const a = new MyClass('Bob');
//duplicate identifier in MyClass.d.ts
like image 868
tarling Avatar asked Oct 29 '22 12:10

tarling


2 Answers

I would try something like this

declare class MyClass {
    greet(): void;
}

declare type MyClassFactory = (x: string) => MyClass

const factory = (require('./MyClass') as any).MyClass as MyClassFactory;
const a = factory('Bob');

which is to detach the class and its constructor function

like image 148
robkuz Avatar answered Nov 02 '22 23:11

robkuz


So the first problem is that your declaration file is for the MyClass module and defines the class but doesn't describe that modules exports. The second problem is that you then need the matching import statement in your main module. import './MyClass' is only to import side effects (see the typescript modules doc.

Based on the code that works, it looks like the MyClass module exports an object with a MyClass property (set to the MyClass class) so that's what I've added to your declaration file.

The MyClass.d.ts declaration file for the js module:

declare class MyClass {
  constructor(name: string);
  greet(): void;
}

export { MyClass }

Then in your main.ts:

import { MyClass } from './MyClass';

let a = new MyClass('foo');
a.greet();
like image 29
Mike Lippert Avatar answered Nov 02 '22 23:11

Mike Lippert