Implementazione dell’interfaccia TypeScript con la firma della funzione nuda e altri campi

Come scrivere una class che implementa questa interfaccia TypeScript (e mantiene felice il compilatore TypeScript):

interface MyInterface { (): string; text2(content: string); } 

Ho visto questa risposta correlata: come fare una class implementare una firma di chiamata in Typescript?

Ma funziona solo se l’interfaccia ha solo la firma della funzione nuda. Non funziona se si dispone di membri aggiuntivi (come la funzione text2) da implementare.

Una class non può implementare tutto ciò che è disponibile in un’interfaccia typescript. Due esempi principali sono le firme chiamabili e le operazioni sugli indici, ad esempio: Implementare un’interfaccia indicizzabile

Il motivo è che un’interfaccia è progettata principalmente per descrivere tutto ciò che gli oggetti JavaScript possono fare. Quindi ha bisogno di essere davvero robusto. Una class TypeScript tuttavia è progettata per rappresentare in modo specifico l’ereditarietà del prototipo in un modo più OO convenzionale / facile da comprendere / facile da scrivere.

Puoi ancora creare un object che segue quell’interfaccia:

 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; } ); 

C’è un modo semplice e sicuro per farlo con Object.assign di ES6:

 const foo: MyInterface = Object.assign( // Callable signature implementation () => 'hi', { // Additional properties text2(content) { /* ... */ } } ) 

I tipi di intersezione, che non credo fossero disponibili in TypeScript quando questa domanda è stata inizialmente posta e data risposta, sono la salsa segreta per ottenere la digitazione corretta.

Ecco un’elaborazione sulla risposta accettata .

Per quanto ne so, l’unico modo per implementare una firma di chiamata è usare una funzione / metodo. Per implementare i membri rimanenti, basta definirli su questa funzione. Questo potrebbe sembrare strano agli sviluppatori provenienti da C # o Java, ma penso che sia normale in JavaScript.

In JavaScript, questo sarebbe semplice perché puoi semplicemente definire la funzione e quindi aggiungere i membri. Tuttavia, il sistema di tipi di TypeScript non lo consente perché, in questo esempio, Function non definisce un membro text2 .

Quindi, per ottenere il risultato desiderato, è necessario ignorare il sistema di tipi mentre si definiscono i membri sulla funzione e quindi è ansible trasmettere il risultato al tipo di interfaccia:

 //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 result; })(); //Invokes the closure to produce the implementation 

Si noti che non è necessario utilizzare una chiusura. Si potrebbe semplicemente dichiarare la variabile temporanea nello stesso ambito dell’implementazione dell’interfaccia risultante. Un’altra opzione è denominare la funzione di chiusura per migliorare la leggibilità.

Ecco quello che penso sia un esempio più realistico:

 interface TextRetriever { (): string; Replace(text: string); } function makeInMemoryTextRetriever(initialText: string) { var currentText = initialText; var instance: any = () => currentText; instance.Replace = (newText: string) => currentText = newText; return instance; } var inMemoryTextRetriever = makeInMemoryTextRetriever("Hello");