En règle générale, vous devez faire référence aux classes dans le langage de programmation en utilisant leur type de constructeur. Toutefois, à partir de la version 2.8 de typescript, il existe un nouveau type de constructeur. InstanceType<T>
dans la bibliothèque standard qui peut extraire le type d'instance du type de constructeur. Vous pouvez l'utiliser ici pour obtenir la sécurité de type que vous souhaitez.
Pour votre extrait, vous pouvez ajouter des types comme suit :
class Messages {
getMessage<T extends {getMessage: () => string, new (...args: any[]): InstanceType<T>}>(classRef: T): string {
// Here, classRef is properly inferred to have a `getMessage` method.
return classRef.getMessage()
}
}
class myClassA {
constructor(public id: number, public message: string) {}
static getMessage(): string {
return 'hello from class A';
}
}
class myClassB {
constructor(public id: number, public message: string) {}
static getMessage(): string {
return 'hello from class B';
}
}
var messages = new Messages();
// messageA and messageB inferred to have type: string
// You can change that back to any if you want.
// myClassA and myClassB both assignable as the argument to
// getMessage, so no problem there.
var messageA = messages.getMessage(myClassA);
var messageB = messages.getMessage(myClassB);
console.log(messageA) // 'hello from class A'
console.log(messageB) // 'hello from class B'
La ligne
getMessage<T extends {getMessage: () => string, new (...args: any[]): InstanceType<T>}>(classRef: T): string {
est l'origine de la sécurité du type. Cette syntaxe dit que tout ce qui T
est, il doit avoir une méthode getMessage
(donc si T est un constructeur de classe, getMessage
doit être une méthode statique), et la méthode new (...args: any[]): InstanceType<T>
signifie que T
doit être un constructeur de classe.
J'ai défini les arguments du constructeur comme étant n'importe quoi ici, mais si vous savez que le constructeur prendra toujours des arguments spécifiques, vous pouvez encore les restreindre. Pour votre exemple, new (id: number, message: string): InstanceType<T>
fonctionnerait.
Sans typescript 2.8, vous ne pouvez pas utiliser InstanceType
. Mais vous pouvez toujours obtenir une sécurité de type ici en laissant T
représente le type d'instance, puis définit le type du paramètre comme étant un type enveloppé qui utilise la fonction T
comme paramètre. Donc, pour votre exemple :
interface Messageable<T> {
new(...args: any[]): T;
getMessage(): string;
}
class Messages {
getMessage<T>(classRef: Messageable<T>): string {
return classRef.getMessage()
}
}
devrait fonctionner.