Comment puis-je écrire une classe qui implémente cette interface TypeScript (et maintient le compilateur TypeScript heureux):
interface MyInterface {
(): string;
text2(content: string);
}
J'ai vu cette réponse connexe: Comment faire pour qu'une classe implémente une signature d'appel dans Typescript?
Mais cela ne fonctionne que si l'interface n'a que la signature de fonction nue. Cela ne fonctionne pas si vous avez des membres supplémentaires (comme la fonction text2) à implémenter.
Une classe ne peut pas implémenter tout ce qui est disponible dans une interface TypeScript. Deux exemples principaux sont les signatures appelables et les opérations d'index, par exemple : Implémenter une interface indexable
La raison en est qu'une interface est principalement conçue pour décrire tout ce que les objets JavaScript peuvent faire. Par conséquent, il doit être vraiment robuste. Une classe TypeScript est cependant conçue pour représenter spécifiquement l'héritage du prototype d'une manière plus OO conventionnelle/facile à comprendre/facile à taper).
Vous pouvez toujours créer un objet qui suit cette interface:
interface MyInterface {
(): string;
text2(content: string);
}
var MyType = ((): MyInterface=>{
var x:any = function():string { // Notice the any
return "Some string"; // Dummy implementation
}
x.text2 = function(content:string){
console.log(content); // Dummy implementation
}
return x;
}
);
Il existe un moyen simple et sûr de le faire avec l'ES6 Object.assign
:
const foo: MyInterface = Object.assign(
// Callable signature implementation
() => 'hi',
{
// Additional properties
text2(content) { /* ... */ }
}
)
Les types d'intersection, qui, je pense, n'étaient pas disponibles dans TypeScript lorsque cette question a été posée et répondue à l'origine, sont la solution secrète pour obtenir le bon typage.
Voici une élaboration sur la réponse acceptée .
Pour autant que je sache, la seule façon d'implémenter une signature d'appel est d'utiliser une fonction/méthode. Pour implémenter les membres restants, il suffit de les définir sur cette fonction. Cela peut sembler étrange aux développeurs venant de C # ou de Java, mais je pense que c'est normal en JavaScript.
En JavaScript, cela serait simple car vous pouvez simplement définir la fonction puis ajouter les membres. Cependant, le système de types de TypeScript ne permet pas cela car, dans cet exemple, Function
ne définit pas un text2
membre.
Ainsi, pour obtenir le résultat souhaité, vous devez contourner le système de types pendant que vous définissez les membres sur la fonction, puis vous pouvez convertir le résultat en type d'interface:
//A closure is used here to encapsulate the temporary untyped variable, "result".
var implementation = (() => {
//"any" type specified to bypass type system for next statement.
//Defines the implementation of the call signature.
var result: any = () => "Hello";
//Defines the implementation of the other member.
result.text2 = (content: string) => { };
//Converts the temporary variable to the interface type.
return <MyInterface>result;
})(); //Invokes the closure to produce the implementation
Notez que vous n'avez pas besoin d'utiliser une fermeture. Vous pouvez simplement déclarer votre variable temporaire dans la même portée que l'implémentation d'interface résultante. Une autre option consiste à nommer la fonction de fermeture pour améliorer la lisibilité.
Voici ce que je pense être un exemple plus réaliste:
interface TextRetriever {
(): string;
Replace(text: string);
}
function makeInMemoryTextRetriever(initialText: string) {
var currentText = initialText;
var instance: any = () => currentText;
instance.Replace = (newText: string) => currentText = newText;
return <TextRetriever>instance;
}
var inMemoryTextRetriever = makeInMemoryTextRetriever("Hello");