Hur kan jag specificera att en typ är en instans av en given klastyp i TypeScript?
Jag vill skapa en Constructor-typ som tar en klass som en typparameter och returnerar signaturen för dess konstruktor.
Detta skulle vara användbart för att definiera en statisk egenskap make-metod på en klass som kan skapa en instans av den klassen istället för att skapa den med ett new ClassInstance(...)-uttryck.
Det här är vad jag har hittills:
type ClassConstructorArgs<T> = T extends { new (...args: infer A): any }
? A
: never;
type Constructor<T> = (...args: ClassConstructorArgs<T>) => T;
class Person {
constructor(public name: string, public age: number) {}
static make: Constructor<typeof Person> = (...args) => new Person(...args);
// ^^^^^^^^^^^^^^^^^^^
// Type 'Person' is missing the following properties from type 'typeof Person': prototype, make
}
Problemet är att den statiska make har ett fel: Typen 'Person' saknar följande egenskaper från typen 'typeof Person': prototype, make
Jag förstår att detta beror på att min Constructor-typ är fel, konstruktörer av klassen T returnerar inte klassen T själv utan en instans av T.
Men sedan vet jag inte hur jag kan uttrycka att Constructor returnerar en instans av T snarare än klassen T själv. Är det ens möjligt i TypeScript?
Svar #1
Typescript har inbyggda verktyg både för ConstructorParameters och InstanceType:
type Constructor<T extends new (...args: any) => any> =
(...args: ConstructorParameters<T>) => InstanceType<T>;
class Person {
constructor(public name: string, public age: number) {}
static make: Constructor<typeof Person> = (...args) => new Person(...args);
}
const p = Person.make('some name', 1); // p is of type Person
Lekplats
Om du undrar hur dessa verktyg definieras och vad som är fel med ditt försök, här är det:
type ConstructorParameters<T extends new (...args: any) => any> =
T extends new (...args: infer P) => any ? P : never;
type InstanceType<T extends new (...args: any) => any> =
T extends new (...args: any) => infer R ? R : any;
Källa
