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?

1127voto

Ryan Cavanaugh Punkte 204278

Sicher. Die Funktion Typ besteht aus den Typen seines Arguments und seines Rückgabetyps. Hier legen wir fest, dass die callback Der Typ des Parameters muss "Funktion, die eine Zahl annimmt und den Typ zurückgibt" sein. any ":

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

var strCallback = (result: string) : void => {
    alert(result);
}
var numCallback = (result: number) : void => {
    alert(result.toString());
}

foo.save(strCallback); // not OK
foo.save(numCallback); // OK

Wenn Sie möchten, können Sie eine Typ-Alias um dies zu kapseln:

type NumberCallback = (n: number) => any;

class Foo {
    // Equivalent
    save(callback: NumberCallback) : void {
        callback(42);
    }
}

112voto

Drew Noakes Punkte 282438

Hier sind TypeScript-Äquivalente einiger gängiger .NET-Delegate:

interface Action<T>
{
    (item: T): void;
}

interface Func<T,TResult>
{
    (item: T): TResult;
}

27voto

Krishna Ganeriwal Punkte 1743
type FunctionName = (n: inputType) => any;

class ClassName {
    save(callback: FunctionName) : void {
        callback(data);
    }
}

Dies entspricht sicherlich dem Paradigma der funktionalen Programmierung.

19voto

kbpontius Punkte 3677

Ich weiß, dass dieser Beitrag schon alt ist, aber es gibt einen kompakteren Ansatz, der sich von der Fragestellung leicht unterscheidet, aber eine sehr hilfreiche Alternative sein kann. Sie können die Funktion im Wesentlichen in-line deklarieren, wenn Sie die Methode aufrufen ( Foo 's save() in diesem Fall). Es würde etwa so aussehen:

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

    multipleCallbacks(firstCallback: (s: string) => void, secondCallback: (b: boolean) => boolean): void {
        firstCallback("hello world")

        let result: boolean = secondCallback(true)
        console.log("Resulting boolean: " + result)
    }
}

var foo = new Foo()

// Single callback example.
// Just like with @RyanCavanaugh's approach, ensure the parameter(s) and return
// types match the declared types above in the `save()` method definition.
foo.save((newNumber: number) => {
    console.log("Some number: " + newNumber)

    // This is optional, since "any" is the declared return type.
    return newNumber
})

// Multiple callbacks example.
// Each call is on a separate line for clarity.
// Note that `firstCallback()` has a void return type, while the second is boolean.
foo.multipleCallbacks(
    (s: string) => {
         console.log("Some string: " + s)
    },
    (b: boolean) => {
        console.log("Some boolean: " + b)
        let result = b && false

        return result
    }
)

En multipleCallback() Ansatz ist sehr nützlich für Dinge wie Netzwerkanrufe, die erfolgreich sein oder fehlschlagen können. Nehmen wir wieder das Beispiel eines Netzwerkaufrufs, wenn multipleCallbacks() aufgerufen wird, kann das Verhalten bei Erfolg und Misserfolg an einer Stelle definiert werden, was für künftige Code-Leser zu mehr Klarheit führt.

Meiner Erfahrung nach ist dieser Ansatz in der Regel prägnanter, weniger unübersichtlich und insgesamt klarer.

Viel Glück für alle!

8voto

Willem van der Veen Punkte 26043

In TS können wir Funktionen auf die folgende Weise eingeben:

Funktionsarten/Signaturen

Diese wird für echte Implementierungen von Funktionen/Methoden verwendet und hat die folgende Syntax:

(arg1: Arg1type, arg2: Arg2type) : ReturnType

Ejemplo:

function add(x: number, y: number): number {
    return x + y;
}

class Date {
  setTime(time: number): number {
   // ...
  }

}

Funktionstyp Literale

Funktionstyp-Literale sind eine weitere Möglichkeit, den Typ einer Funktion zu deklarieren. Sie werden normalerweise in der Funktionssignatur einer Funktion höherer Ordnung verwendet. Eine Funktion höherer Ordnung ist eine Funktion, die Funktionen als Parameter akzeptiert oder die eine Funktion zurückgibt. Sie hat die folgende Syntax:

(arg1: Arg1type, arg2: Arg2type) => ReturnType

Ejemplo:

type FunctionType1 = (x: string, y: number) => number;

class Foo {
    save(callback: (str: string) => void) {
       // ...
    }

    doStuff(callback: FunctionType1) {
       // ...
    }

}

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