Wie lautet die Syntax für Typescript-Pfeilfunktionen mit Generika?


192

Das Typoskript-Handbuch enthält derzeit keine Pfeilfunktionen. Normale Funktionen können generisch mit folgender Syntax eingegeben werden: Beispiel:

function identity<T>(arg: T): T {
    return arg;
}

Wie lautet die Syntax für Pfeilfunktionen?

Antworten:


228

Das vollständige Beispiel, das die Syntax erklärt, auf die Robin verweist, brachte es für mich nach Hause:

Generische Funktionen

So etwas funktioniert gut:

function foo<T>(x: T): T { return x; }

Die Verwendung einer generischen Pfeilfunktion führt jedoch nicht zu:

const foo = <T>(x: T) => x; // ERROR : unclosed `T` tag

Problemumgehung: Verwenden Sie die Erweiterung des generischen Parameters, um den Compiler darauf hinzuweisen, dass es sich um einen generischen Parameter handelt, z.

const foo = <T extends unknown>(x: T) => x;

1
Wäre es möglich, einen vordefinierten generischen Typ für zu deklarieren const foo? dh type GenericFun<T, A=T> = (payload: A) => T;dann const foo: GenericFunnoch generisch machen ohne einen Ttyp anzugeben?
Ciekawy

@ciekawy, AFAIK, ist es nicht, und ich denke, das macht Sinn. Bei Generika geht es in gewissem Sinne darum, Typen höherer Ordnung zuzulassen. GenericFun<T, A=T>definiert eine Menge, die unter anderem andere Typen GenericFun<number> und enthält GenericFun<string>. Das Zulassen, dass generische Typen direkt eine Typanmerkung darstellen - z. B. const const foo: GenericFun- würde jedoch dazu neigen, die statische Sicherheit zu const foo: GenericFun<string>const foo: GenericFun<number>
untergraben

7
Ihr zweites Beispiel ist nur ein Fehler in einer .tsxDatei (TypeScript + JSX). In einer .tsDatei funktioniert es einwandfrei, wie Sie auf dem TypeScript-Spielplatz sehen können .
Danvk

46
Neuere Typoskript-Compiler unterstützen auch nachgestellte Kommas const foo = <T,>(x: T) => x;, um die JSX-Mehrdeutigkeit zu umgehen.
Thomas

1
@danvk Bemerkenswert ist, dass dies nur für diejenigen gilt, die JSX in TS-Dateien verboten haben. Wenn ein Projekt so konfiguriert ist, dass JSX in TS-Dateien zulässig ist, benötigen Sie weiterhin das "Erweitert" oder das nachfolgende Komma
Matt

63

Ich fand das obige Beispiel verwirrend. Ich verwende React und JSX, daher denke ich, dass dies das Szenario kompliziert hat.

Ich habe von TypeScript Deep Dive eine Klarstellung erhalten , in der für Pfeilgenerika Folgendes angegeben ist:

Problemumgehung: Verwenden Sie die Erweiterung des generischen Parameters, um den Compiler darauf hinzuweisen, dass es sich um einen generischen Parameter handelt. Dies stammt aus einem einfacheren Beispiel, das mir geholfen hat.

    const identity = < T extends {} >(arg: T): T => { return arg; }

8
"T erweitert jeden" würde dann void unterstützen.
Mohamed Fakhreddine

48

Wenn Sie sich in einer .tsxDatei befinden, können Sie nicht einfach schreiben <T>, aber das funktioniert:

const foo = <T, >(x: T) => x;

Im Gegensatz zum extends {}Hack bewahrt dieser Hack zumindest die Absicht.


Planen sie, dieses Verhalten zu beheben?
Alexander Kim

Ich denke, es gibt nicht viel, was man dagegen tun könnte ... die generischen Syntaxen JSX und Typescript kollidieren hier einfach ..
mb21

1
Fantastisch - das ist bei weitem die beste Antwort: Funktioniert perfekt und verändert das Verhalten überhaupt nicht!
Geoff Davids

Was ist mit dem Standardtyp-Parametertyp? const foo = <T = any,>(x: T) => xfunktioniert nicht ...
Mikhail Vasin

34

Die Sprachspezifikation sagt auf S.64f

Ein Konstrukt der Form <T> (...) => {...} kann als Pfeilfunktionsausdruck mit einem Typparameter oder als Typzusicherung analysiert werden, die auf eine Pfeilfunktion ohne Typparameter angewendet wird. Es wird als erstere gelöst [..]

Beispiel:

// helper function needed because Backbone-couchdb's sync does not return a jqxhr
let fetched = <
           R extends Backbone.Collection<any> >(c:R) => {
               return new Promise(function (fulfill, reject) {
                   c.fetch({reset: true, success: fulfill, error: reject})
               });
           };


3

Während die populäre Antwort mit extends {}funktioniert und besser ist als extends any, zwingt sie das T, ein Objekt zu sein

const foo = <T extends {}>(x: T) => x;

Um dies zu vermeiden und die Typensicherheit zu erhalten, können Sie extends unknownstattdessen verwenden

const foo = <T extends unknown>(x: T) => x;

1

Ich benutze diese Art von Erklärung:

const identity: { <T>(arg: T): T } = (arg) => arg;

Es ermöglicht das Definieren zusätzlicher Requisiten für Ihre Funktion, falls dies jemals erforderlich sein sollte, und in einigen Fällen hilft es dabei, den Funktionskörper sauberer von der generischen Definition zu halten.

Wenn Sie keine zusätzlichen Requisiten benötigen (Namespace), können Sie dies vereinfachen:

const identity: <T>(arg: T) => T = (arg) => arg;

1

so spät, aber mit ES6 keine Notwendigkeit verlängert es funktioniert immer noch für mich .... :)

let getArray = <T>(items: T[]): T[] => {
    return new Array<T>().concat(items)
}

let myNumArr = getArray<number>([100, 200, 300]);
let myStrArr = getArray<string>(["Hello", "World"]);
myNumArr.push(1)
console.log(myNumArr)

Das funktioniert bei mir nicht, ich muss ein Komma wie folgt hinzufügen : <T, >. wie in @Thomas Kommentar unter @jbmilgrom 'Antwort beschrieben
Apollo

Sie sollten die anderen Lösungen lesen, bevor Sie eine veröffentlichen. Ihre Lösung wurde bereits mit Erläuterungen veröffentlicht. Es funktioniert nur innerhalb einer .ts-Datei, nicht innerhalb einer .tsx-Datei.
Isaac Pak
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.