Skillnaden mellan funktionsdeklarationer i TypeScript
Låt oss säga att vi har kod som detta:
interface Vehicle {
bicycle(): string;
car(wheel: number): void;
bus(passanger: number): {
name: string;
age: number;
}[];
}
type Mapper<K extends keyof Vehicle> = (funcName: K, callback: Vehicle[K]) => void;
interface MapperB {
<K extends keyof Vehicle>(name: K, callback: Vehicle[K]): any;
}
declare const caller: Mapper<keyof Vehicle>;
declare const callerB: MapperB
Eller TypeScript-lekplats här.
Och när jag kallar caller och callerB, kan caller inte härleda callback-typen enligt det första argumentet. Faktiskt, jag upptäckte att det inte finns något sätt att uppnå det. Men callerB fungerar bara helt korrekt.
caller("bicycle", () => {
})// can't give any intellisense
callerB('bus', (passanger) => {
return [{
name: 'Jack',
age: 11
}]
})// will give perfect hints according to first argument.
Så jag undrade vad skillnaden är mellan de två deklarationerna, det verkar inte vara ett fel🐶.
Svar #1
En är en generisk typ som råkar vara en funktion (Mapper), den andra är en generisk funktion (MapperB).
En generisk typ har sina typ parametrar specificerade när du deklarerar caller, så ingen ytterligare inferens sker när du anropar caller. K har redan fastställts, och K kommer att vara unionen 'bicycle' | 'car' | 'bus'. Så callback kommer att typas som Vehicle['bicycle' | 'car' | 'bus'], vilket kommer att vara en union av alla funktionssignaturer i Vehicle, vilket förmodligen kommer att vara för generöst för vad du vill.
En generell funktion har sina typ-parameter specificerade (eller härledda) när funktionen anropas. Så det är vid den tidpunkten, baserat på typen av argumentet, som K beslutas att vara just bus och callback-parametrarna kan härledas mer exakt.
Du kan deklarera en generisk funktion med en typalias, men listan över generiska typparametrar måste vara på funktionen och inte på typen:
type Mapper = <K extends keyof Vehicle>(funcName: K, callback: Vehicle[K]) => void;
Lekplatslänk
Svar #2
Din Mapper-typ är generisk och returnerar en icke-generisk funktion (typparametrarna i funktionen utökas efter att ha tagit emot ett generiskt typargument), vilket betyder att K är keyof Vehicle och inte den specifika nyckel som du är ute efter. MapperB-typen är inte generisk, men har istället en generisk funktion, vilket betyder att typvariablerna utökas vid funktionsanrop, vilket innebär att K kan justeras till att vara den specifika nyckeln av Vehicle.
