typescript - Inferred typ i generisk med flera typparametrar


Jag försöker sätta upp en generisk där parametern är nyckeln till ett annat objekt. Jag kan åstadkomma detta genom att använda extends keyof när båda typerna är parametrar till funktionen.

Men när typen som tillhandahåller listan över nycklar inte är ett argument, utan bara en generisk typ, kräver TypeScript att båda generiska typerna sätts.

Överväg följande kod:

interface Bar {
  z: string;
  t: number;
}

declare function foo1<T extends keyof Bar>(x: T)
let t1 = foo1('z');

declare function foo2<K, T extends keyof K>(x: T)
let t2 = foo2<Bar>('t');

declare function foo3<T>(x: T)
let t3 = foo3<keyof Bar>('t');

Länk till lekplats

Funktionen foo2 misslyckas eftersom den andra typen T inte är angiven. Jag känner dock att TS borde kunna härleda de korrekta typerna utan en uttrycklig andra typ.

foo3 är min lösning, men den är inte lika trevlig att arbeta med. Är det möjligt att låta TypeScript göra denna inferens, eller kommer detta att vara en funktionförfrågan/felrapport till TS-teamet?

Svar #1

Du är nära med foo2. Här är vad det ska vara för att få det att fungera.

declare function foo2<T, K = keyof T>(x: K)
let t2 = foo2<Bar>('t');

Istället för att förvänta sig en ny generisk typparameter kan du tilldela en till en typ (i det här fallet typen av T).

Det är också möjligt att direkt tilldela parametrarnas typ till keyof för den givna generiska typen T.

declare function foo4<T>(x: keyof T);
let t4 = foo4<Bar>('t');

Svar #2

Det finns redan ett framstående förslag för partiell inferens av typparametrar (utan att använda standardvärden) på Microsoft/TypeScript#14400. För tillfället kan du inte göra det. Istället kommer jag att ge dig en lösning som jag ofta föreslår i fall som detta: curryerade funktioner.

declare function curriedFoo<B>(): <T extends keyof B>(x: T)=>any;
let t4 = curriedFoo<Bar>()('t'); // okay

Funktionen utan argument curriedFoo() tar en typparameter B (jag kan inte använda K till något annat än en nyckel, förlåt), och returnerar en funktion av den typ du egentligen vill ha, begränsad till att endast acceptera en T extends keyof B-parameter (här är det jag skulle vilja använda K, men det gör inget).

Det är lite klumpigt men det gör jobbet. Hoppas det hjälper; lycka till!

Relaterade artiklar