2013-05-12 4 views
27

Come faccio a scrivere una classe che implementa questa interfaccia dattiloscritto (e mantiene il compilatore dattiloscritto felice):interfaccia Implementazione dattiloscritto con firma funzione di nudo più altri campi

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

ho visto questa risposta correlato: How to make a class implement a call signature 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.

+0

http://stackoverflow.com/questions/16248812/implement-an-indexible-interface#comment23254752_16248812 – basarat

+0

risposta breve è "classi non può corrispondere tale interfaccia" di cui parla la questione si è collegato http://stackoverflow.com/a/12770145/390330 – basarat

risposta

32

Una classe non può implementare tutto ciò che è disponibile in un'interfaccia dattiloscritto. Due primi esempi sono le firme chiamabili e le operazioni sugli indici, ad es. : Implement an indexible interface

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 classe TypeScript tuttavia è progettata per rappresentare in modo specifico l'ereditarietà del prototipo in un modo più OO convenzionale/facile da comprendere/facile da scrivere.

È comunque possibile creare un oggetto che segue tale 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; 
} 
); 
9

Ecco un'elaborazione su the accepted answer.

Per quanto ne so, l'unico modo per implementare una firma di chiamata è utilizzare 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é è possibile 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 bypassare il sistema di tipo mentre si definiscono i membri sulla funzione, e quindi si può lanciare il risultato per il 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 <MyInterface>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 è 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 <TextRetriever>instance; 
} 

var inMemoryTextRetriever = makeInMemoryTextRetriever("Hello"); 
6

C'è un modo semplice e type-safe per fare questo con Object.assign di ES6:

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

tipi intersezione, che I don' Penso che fossero disponibili in TypeScript quando questa domanda è stata inizialmente posta e risposta, sono la salsa segreta per ottenere la digitazione corretta.

+0

Questo non è del tutto sicuro dal momento che '' Object.assign'' restituisce '' any''. – Flavien

+1

Nella versione attuale di TS è 'assegnare (destinazione: T, fonte: U): T & U' –

+0

@Flavien le firme correnti sono simili a questo: https://github.com/Microsoft/TypeScript/blob/master /lib/lib.es6.d.ts#L4438 –