Koja je sintaksa za TypeScript streličaste funkcije s generičkim tipovima?


Priručnik za TypeScript trenutno nema ništa o streličnim funkcijama. Normalne funkcije mogu se generički tipizirati ovom sintaksom: primjer:

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

Koja je sintaksa za funkcije strelice?

Odgovor #1

Uredi

Prema @Thomas komentaru, u novijim TS kompajlerima možemo jednostavno napraviti:

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

Izvorni odgovor

Cjeloviti primjer koji objašnjava sintaksu na koju je Robin referirao... učinio je da mi to postane jasno:

Generičke funkcije

Nešto poput sljedećeg funkcionira dobro:

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

Međutim, korištenje generičke funkcije sa strelicom neće:

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

Zaobilazno rješenje: Koristite extends na generičkom parametru kako biste naznačili kompajleru da je generički, npr.:

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

Odgovor #2

Ako ste u datoteci .tsx, ne možete samo napisati <T>, ali ovo radi:

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

Za razliku od hakiranja extends {}, ovo hakiranje barem očuva namjeru.

Odgovor #3

Primjer iznad mi je bio zbunjujući. Koristim React i JSX, pa mislim da je to zakompliciralo situaciju.

Dobio sam pojašnjenje iz TypeScript Deep Dive, koji navodi za generičke strelice:

Zaobilazno rješenje: Koristite extends na generičkom parametru kako biste dali do znanja kompajleru da je generički, ovo je proizašlo iz jednostavnijeg primjera koji mi je pomogao.

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

Odgovor #4

Ovo mi odgovara

const Generic = <T> (value: T) => {
    return value;
} 

Odgovor #5

Specifikacija jezika navodi na str. 64 i sl.

Konstrukcija oblika < T > ( ... ) => { ... } mogla bi se tumačiti kao izraz streličaste funkcije s parametrom tipa ili kao tvrdnja o tipu primijenjena na streličastu funkciju bez parametra tipa. Rješava se kao prvo[..]

primjer :

// 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})
               });
           };

Odgovor #6

tako kasno, ali s ES6 nema potrebe za extends, i dalje mi radi.... :)

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)

Odgovor #7

Ovo mi odgovara

const logSomething = <T>(something:T): T => {
    return something;
}

Odgovor #8

Koristim ovu vrstu deklaracije:

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

Omogućuje definiranje dodatnih svojstava za vašu funkciju ako ikada zatrebate, a u nekim slučajevima pomaže održati tijelo funkcije čišćim od generičke definicije.

Ako vam dodatni atributi (nešto poput prostora imena) nisu potrebni, to se može pojednostaviti na:

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

Odgovor #9

iako popularan odgovor s extends {} radi i bolji je od extends any, on prisiljava T da bude objekt

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

da biste to izbjegli i sačuvali sigurnost tipa, možete koristiti extends unknown umjesto toga

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

Odgovor #10

Način bez korištenja arrow funkcija. Proširujući primjer iz OP-a.

function foo<T>(abc: T): T {
    console.log(abc);
    return abc;
}

const x = { abc: 123 };
foo(x);

const y = 123;
foo<number>(y);

Osim odgovora koji uključuje umetanje cijele stvari u jednu izjavu:

const yar = <T,>(abc: T) => {
    console.log(abc);
    return abc;
}

Drugi pristup je imati međutip:

type XX = <T>(abc: T) => T;

const bar: XX = (abc) => {
    console.log(abc);
    return abc;
}

Igralište

Povezani članci