I've been trying to understand if there is any difference between using InstanceType
to assign a type, or simply using the Class name.
In particular, given the class:
MyClass {
public static foo: string = 'abc'
public makeFoo() {
// awesome maker
}
}
When I want to use an instance of the class, it seems that there is no difference between:
// inside some other Class
private myClassInstance: InstanceType<typeof MyClass>
...
this.myClassInstance = new MyClass()
and
// inside some other Class
private myClassInstance: MyClass
...
this.myClassInstance = new MyClass()
At least in VSCode I don't get any visible difference in using any of the two. However I guess a difference must exist, if TS has implemented InstanceType<>
.
Anyone knows if there is a difference?
CodePudding user response:
The InstanceType
helper type exists because there are actually two things:
- Classes are actually functions in JavaScript (more precisely constructor functions, but mainly functions)
- The return of these constructor functions is of one certain type (the
prototype
of the constructor function and optionally some instance fields)
In TypeScript, when you declare a class
, you actually declare both things: a constructor function and the type of the generated instances (class fields and methods).
In your example, when you write class MyClass
you actually create one JavaScript class and two TypeScript types:
MyClass
: a kind of interface which contains the class fields and methodstypeof MyClass
(in this caseMyClass
refers to the runtime class): the constructor function
As you didn't specify a constructor function, its type is new () => MyClass
and you can extract MyClass
out of it thanks to InstanceType
.
As a real-world example, imagine you are trying to implement a factory (function that returns instances of classes). One naive implementation would look like this:
declare function factory<T>(ctor: T): T;
class A { }
const res = factory(A); // typeof A: not what we expect
This doesn't work because we actually return the type of the constructor function itself.
However, this implementation works:
type Constructor = new (...args: any[]) => any;
declare function factory<T extends Constructor>(ctor: T): InstanceType<T>;
class A { }
const res = factory(A); // A: what we expect
Because InstanceType
helped us declare that the return value type is the constructor's return value type.