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?

Andreas Frische
quelle

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;
jbmilgrom
quelle
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; }
Robin Luiten
quelle
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.

mb21
quelle
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})
               });
           };
Andreas Frische
quelle
13

Das funktioniert bei mir

const Generic = <T> (value: T) => {
    return value;
} 
Harshit Singhai
quelle
2
Wenn In .tsDatei funktioniert dies. Ansonsten muss man verlängern.
Kushalvm
1
Funktioniert einwandfrei: typescript-play.js.org/#code/…
Alireza
Dies funktioniert gut für mich in .ts- und .tsx-Dateien in vscode
Shubhan
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;
Michal Filip
quelle
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;
Roy Art
quelle
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)
Bär
quelle
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