How can I make old style classes work in typescript?

生来就可爱ヽ(ⅴ<●) 提交于 2019-11-27 08:09:57

问题


While converting a large number of files to typescript, I have many classes declared this way.

function FooClass() {
    this.bar = 1; // error TS2683: 'this' implicitly has type 'any'
                  // because it does not have a type annotation.
}

FooClass.prototype.myMethod = function() {
    // ...
}

How can I make this work with strict type checking turned on, while avoiding rewriting it all using class syntax?


回答1:


The easiest way to get the above code to work is to add a this parameter to the function, like so:

function FooClass(this: {bar: number}) {
    this.bar = 1; // okay
}

Unfortunately, you will soon find that the compiler doesn't know what to make of FooClass when you treat it like a constructor:

const oops = new FooClass(); // error, oops is implicitly any
oops.bar // okay but compiler has no idea
oops.myMethod() // okay but also no idea
oops.foo // also okay, but you probably don't want it to be
oops.yourMethod() // ditto

This is apparently by design. The best way to annotate this, in my opinion, is to define the types FooClass and FooConstructor in advance:

interface FooClass {
  bar: number;
  myMethod(): void;
}

interface FooConstructor {
  new(): FooClass,
  prototype: FooClass
}

Note that when you use the class FooClass {} way of creating constructors, TypeScript automatically generates both a value FooClass which is the constructor itself, and a type FooClass which is the type of the instances created by the constructor. This is often confusing to developers, so take care. We are doing that here manually: the above interface FooClass is the type, not the value, which we are about to create.

After you define those types, assert that the FooClass function is of type FooConstructor when you create it (the assertion needs to pass though Function or any and is not safe, so be careful).

const FooClass = function FooClass(this: FooClass) {
  this.bar = 1;
} as Function as FooConstructor;

FooClass.prototype.myMethod = function () {
  // ...
}

And test it out:

const okay = new FooClass();
okay.bar // number
okay.myMethod() // known
okay.foo // error, yay
okay.yourMethod() // error, yay

Hope that helps; good luck!




回答2:


If you don't want to convert them, I'd suggest to keep them as JavaScript files and just write declaration files for them. Then TypeScript would recognise them implicitly, without rewriting the code.

You could add to your project a types.d.ts file and:

declare class FooClass {
    public bar: number;
    public myMethod: () => void;
    ...
}

With such a file in your project, TypeScript will allow you to do const myClass = new FooClass();.

Of course, you still have to add your JavaScript code (or you'll run into runtime errors), importing it the way that suits you. If you were using global files, by loading them in your page, or in whichever environment you're working on. If your old code was in modules, you import those modules when you need to use them.




回答3:


I noticed that TypeScript v3.6.2 seems to behave differently when in the context of .js files. The following ECMAScript 5 style class seems fortunately to be type inferred and the two expected type offenses detected:

/**
 * @class Person
 * @param {string} name
 */
function Person(name) {
  this.name = name
}

var person = new Person("John")
person.foo // TS2339: Property 'foo' does not exist on type 'Person'.
person.name

new Person(42) // Argument of type '42' is not assignable to parameter of type 'string'.

This could be confirmed with:

$ tsc --checkJs --allowJs --noImplicitAny --strictNullChecks test.js

Reverting back to a .js file therefore could be one way to continue with the original inheritance style.

For subclasses, however, this method seems to break. I've posted the details to https://github.com/microsoft/TypeScript/issues/18171.



来源:https://stackoverflow.com/questions/49799192/how-can-i-make-old-style-classes-work-in-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!