4 votes

Typescript : Passer la classe générique en paramètre de fonction

Je dois passer un class reference en tant que function parameter et invoquer un static method sur cette classe. Dans le futur, je pourrais avoir besoin de créer une instance de la classe et j'ai ajouté un constructeur comme exemple.

J'ai réussi à le faire fonctionner sans taper :

class Messages {
    getMessage(classRef: any): any {
       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();
var messageA = messages.getMessage(myClassA);
var messageB = messages.getMessage(myClassB);

console.log(messageA) // 'hello from class A'
console.log(messageB) // 'hello from class B'

J'essaie de saisir la référence de la classe, éventuellement avec des génériques, mais je ne sais pas comment m'y prendre.

J'ai essayé de faire quelque chose du genre getMessage<C>(classRef: {new(): C;}): any {}... mais rien de tout cela ne fonctionne.

Quelqu'un peut-il m'expliquer comment passer une référence de classe correctement ?

5voto

CRice Points 15212

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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X