Home > Back-end >  Difference in TypeScript between types `InstanceType<typeof MyClass>` and `: MyClass`
Difference in TypeScript between types `InstanceType<typeof MyClass>` and `: MyClass`

Time:12-16

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 methods
  • typeof MyClass (in this case MyClass 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.

  • Related