822 Stimmen

Sind stark typisierte Funktionen als Parameter in TypeScript möglich?

In TypeScript kann ich einen Parameter einer Funktion als Typ Function deklarieren. Gibt es eine "typsichere" Möglichkeit, dies zu tun, die ich übersehe? Betrachten Sie zum Beispiel Folgendes:

class Foo {
    save(callback: Function) : void {
        //Do the save
        var result : number = 42; //We get a number from the save operation
        //Can I at compile-time ensure the callback accepts a single parameter of type number somehow?
        callback(result);
    }
}

var foo = new Foo();
var callback = (result: string) : void => {
    alert(result);
}
foo.save(callback);

Die Speichern-Callback ist nicht Typ sicher, ich gebe es eine Callback-Funktion, wo die Funktion Parameter eine Zeichenfolge ist, aber ich bin es eine Zahl übergeben, und kompiliert ohne Fehler. Kann ich das Ergebnis-Parameter in speichern eine Typ-sichere Funktion?

TL;DR-Version: gibt es ein Äquivalent von einem .NET-Delegat in TypeScript?

5voto

Humayoun_Kabir Punkte 1438

Wenn Sie zuerst den Funktionstyp definieren, sieht es folgendermaßen aus

type Callback = (n: number) => void;

class Foo {
    save(callback: Callback) : void {        
        callback(42);
    }
}

var foo = new Foo();
var stringCallback = (result: string) : void => {
    console.log(result);
}

var numberCallback = (result: number) : void => {
    console.log(result);
}

foo.save(stringCallback); //--will be showing error
foo.save(numberCallback);

Ohne Funktionstyp mit einfacher Eigenschaftssyntax wäre dies der Fall:

class Foo {
    save(callback: (n: number) => void) : void {        
        callback(42);
    }
}

var foo = new Foo();
var stringCallback = (result: string) : void => {
    console.log(result);
}

var numberCallback = (result: number) : void => {
    console.log(result);
}

foo.save(stringCallback); //--will be showing error
foo.save(numberCallback);

Wenn Sie wollen, indem Sie eine Schnittstellenfunktion wie c# generische Delegierte wäre es:

interface CallBackFunc<T, U>
{
    (input:T): U;
};

class Foo {
    save(callback: CallBackFunc<number,void>) : void {        
        callback(42);
    }
}

var foo = new Foo();
var stringCallback = (result: string) : void => {
    console.log(result);
}

var numberCallback = (result: number) : void => {
    console.log(result);
}

let strCBObj:CallBackFunc<string,void> = stringCallback;
let numberCBObj:CallBackFunc<number,void> = numberCallback;

foo.save(strCBObj); //--will be showing error
foo.save(numberCBObj);

5voto

Zachary Dow Punkte 1797

Da man eine Funktionsdefinition und einen anderen Datentyp nicht einfach vereinigen kann, finde ich es nützlich, diese Typen in der Nähe zu haben, um sie stark zu typisieren. Basierend auf der Antwort von Drew.

type Func<TArgs extends any[], TResult> = (...args: TArgs) => TResult; 
//Syntax sugar
type Action<TArgs extends any[]> = Func<TArgs, undefined>; 

Jetzt können Sie jeden Parameter und den Rückgabetyp fest eingeben! Hier ist ein Beispiel mit mehr Parametern als das obige.

save(callback: Func<[string, Object, boolean], number>): number
{
    let str = "";
    let obj = {};
    let bool = true;
    let result: number = callback(str, obj, bool);
    return result;
}

Jetzt können Sie einen Union-Typ schreiben, z. B. ein Objekt oder eine Funktion, die ein Objekt zurückgibt, ohne einen völlig neuen Typ zu erstellen, der möglicherweise exportiert oder konsumiert werden muss.

//THIS DOESN'T WORK
let myVar1: boolean | (parameters: object) => boolean;

//This works, but requires a type be defined each time
type myBoolFunc = (parameters: object) => boolean;
let myVar1: boolean | myBoolFunc;

//This works, with a generic type that can be used anywhere
let myVar2: boolean | Func<[object], boolean>;

2voto

cancerbero Punkte 6226

Neben dem, was andere gesagt haben, ist ein häufiges Problem, die Typen der gleichen Funktion zu deklarieren, die überladen ist. Ein typischer Fall ist die Methode EventEmitter on(), die mehrere Arten von Zuhörern akzeptieren wird. Ähnliches kann passieren, wenn man mit redux actions arbeitet - und dort verwendet man den action type als Literal, um die Überladung zu markieren, im Fall von EventEmitters verwendet man den Eventnamen literalen Typ:

interface MyEmitter extends EventEmitter {
  on(name:'click', l: ClickListener):void
  on(name:'move', l: MoveListener):void
  on(name:'die', l: DieListener):void
  //and a generic one
  on(name:string, l:(...a:any[])=>any):void
}

type ClickListener = (e:ClickEvent)=>void
type MoveListener = (e:MoveEvent)=>void
... etc

// will type check the correct listener when writing something like:
myEmitter.on('click', e=>...<--- autocompletion

1voto

shiva gupta Punkte 19
function callbackTesting(callbacks: {onYes: (data: any) => void,onNo: (data: any) => void,onError: (err: any) => void,}, type: String){
        switch(type){
            case "one": 
            callbacks.onYes("Print yes");
            break;
            case "two": 
            callbacks.onNo("Print no");
            break;
            default:
            callbacks.onError("Print error");
            break;
        }
    }

    const onYes1 = (data: any) : void => {
        console.log(data);
    }
    const onNo1 = (data: any) : void => {
        console.log(data);
    }
    const onError1 = (data: any) : void => {
        console.log(data);
    }

    callbackTesting({onYes: function (data: any)  {onYes1(data);},onNo: function (data: any)  {onNo1(data);},onError: function (data: any)  {onError1(data);}}, "one");

    callbackTesting({onYes: function (data: any)  {onYes1(data);},onNo: function (data: any)  {onNo1(data);},onError: function (data: any)  {onError1(data);}}, "two");

    callbackTesting({onYes: function (data: any)  {onYes1(data);},onNo: function (data: any)  {onNo1(data);},onError: function (data: any)  {onError1(data);}}, "cfhvgjbhkjlkm");

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X