Qual è la sintassi per le funzioni freccia Typescript con generici?


194

Il manuale dattiloscritto attualmente non ha nulla sulle funzioni freccia. Le funzioni normali possono essere tipicamente digitate con questa sintassi: esempio:

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

Qual è la sintassi per le funzioni freccia?

Risposte:


238

L'esempio completo che spiega la sintassi a cui fa riferimento Robin ... me l'ha riportato a casa:

Funzioni generiche

Qualcosa di simile al seguente funziona bene:

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

Tuttavia, l'utilizzo di una funzione generica freccia non:

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

Soluzione alternativa: utilizzare extends sul parametro generico per indicare al compilatore che si tratta di un generico, ad esempio:

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

1
sarebbe possibile dichiarare un tipo generico predefinito per const foo? cioè type GenericFun<T, A=T> = (payload: A) => T;quindi rendere const foo: GenericFunancora generico senza fornire un Ttipo?
ciekawy,

@ciekawy, AFAIK, non lo è, e penso che abbia senso. I generici riguardano il permettere tipi di ordine superiore in un certo senso. GenericFun<T, A=T>definisce un set che include altri tipi GenericFun<number> e GenericFun<string>, tra gli altri. Consentire ai tipi generici di costituire direttamente un'annotazione di tipo - ad es. Const const foo: GenericFun- tenderebbe tuttavia a erodere la sicurezza statica altrimenti fornita richiedendo specificità ad es. const foo: GenericFun<string>Oppureconst foo: GenericFun<number>
jbmilgrom,

7
Il tuo secondo esempio è solo un errore in un .tsxfile (TypeScript + JSX). In un .tsfile funziona benissimo, come puoi vedere nel parco giochi TypeScript .
danvk,

49
I compilatori di dattiloscritti più recenti supportano anche la virgola finale const foo = <T,>(x: T) => x;per eludere l'ambiguità di JSX.
Thomas,

1
@danvk Vale la pena notare che questo vale solo per coloro che hanno proibito JSX nei file TS - se un progetto è configurato per consentire JSX nei file TS, avrai ancora bisogno della "estensione" o della virgola finale
Matt

65

Ho trovato l'esempio sopra confuso. Sto usando React e JSX quindi penso che abbia complicato lo scenario.

Ho ricevuto chiarimenti da TypeScript Deep Dive , che afferma per i generici delle frecce:

Soluzione alternativa: utilizzare estende il parametro generico per suggerire al compilatore che si tratta di un generico, derivato da un esempio più semplice che mi ha aiutato.

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

9
"T estende qualsiasi" supporterebbe quindi il vuoto.
Mohamed Fakhreddine,

48

Se sei in un .tsxfile non puoi semplicemente scrivere <T>, ma funziona:

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

A differenza extends {}dell'hack, questo hack almeno conserva l'intento.


Intendono risolvere questo comportamento?
Alexander Kim,

Immagino che non si possa fare molto al riguardo ... le sintassi generiche JSX e Typescript si scontrano qui ...
mb21

1
Fantastico: questa è di gran lunga la risposta migliore: funziona perfettamente e non altera affatto il comportamento!
Geoff Davids,

1
Che dire del tipo di parametro di tipo predefinito? const foo = <T = any,>(x: T) => xnon funziona ...
Mikhail Vasin

34

La specifica della lingua dice a p.64f

Un costrutto della forma <T> (...) => {...} può essere analizzato come espressione di una funzione freccia con un parametro di tipo o un'asserzione di tipo applicata a una funzione di freccia senza parametro di tipo. Viene risolto come il precedente [..]

esempio:

// 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

mentre la risposta popolare con extends {}funziona ed è meglio di extends any, costringe Ta essere un oggetto

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

per evitarlo e preservare la sicurezza del tipo, è possibile utilizzare extends unknowninvece

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

1

Devo usare questo tipo di dichiarazione:

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

Permette di definire ulteriori oggetti di scena per la tua funzione, se necessario, e in alcuni casi, aiuta a mantenere il corpo più pulito dalla definizione generica.

Se non hai bisogno di oggetti di scena aggiuntivi (specie di spazio dei nomi), può essere semplificato per:

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

1

così tardi, ma con ES6 non c'è bisogno di estenderlo funziona ancora per me .... :)

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)

Questo non funziona per me, devo aggiungere una virgola in questo modo: <T, >. come descritto nel commento di @Thomas nella risposta di @jbmilgrom
apollo

Dovresti leggere le altre soluzioni prima di pubblicarne una. La tua soluzione è già stata pubblicata con una spiegazione. Funziona solo all'interno di un file .ts, non di un file .tsx.
Isaac Pak,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.