typescript - Hur man returnerar ett typat objekt baserat på en funktions argumentarray?
Jag har en funktion som omvandlar arrayvärden till nycklar i ett objekt:
function x(keys: string[]) {
const obj: any = {};
keys.forEach(v => {
obj[v] = 'somevalue...';
});
return obj;
}
const result = x(['a', 'b', 'c']);
console.log(result); // {a: "somevalue...", b: "somevalue...", c: "somevalue..."}
Är det möjligt att tala om för TypeScript att returvärdet av denna funktion kommer att vara {<värden i array>: string} ?
Svar #1
Om din funktion mestadels kallas med konstanter, är det vettigt att använda en generisk typparameter för att fånga de faktiska strängarna som skickas till funktionen i en generisk typparameter. Du kan sedan använda denna typparameter med record för att få ett starkt typat objekt som kommer att ha de nycklar du specificerat.
function x<K extends string>(keys: readonly K[]) {
const obj = {} as Record<K, string>;
keys.forEach(v => {
obj[v] = 'somevalue...';
});
return obj;
}
const result = x(['a', 'b', 'c']); // Record<"a" | "b" | "c", string>, same as {a: string, b: string, c: string}
result.a;
const keys = ['a', 'b', 'c'] as const
const result2 = x(keys);// Record<"a" | "b" | "c", string>
const skeys = ['a', 'b', 'c']// string[]
const result3 = x(keys);// Record<string, string>, same as { [n: string]: string }
Spela
Om funktionen anropas med en array som innehåller string kommer du att få en vanlig indexsignatur, så du kommer inte att ha det sämre med den här versionen.
Svar #2
Eftersom Typescripts typdefinitioner endast är tillgängliga vid kompileringstid finns det inget sätt för det att dra slutsatsen om den informationen vid körning, särskilt om arrayen skapas dynamiskt. (Om dina nycklar är konstanta, ta en titt på Titians lösning.)
För TypeScript är din array en array av strängar.
Du kan ange typen på ditt returobjekt från x-funktionen med indexsignaturen för att undvika any-typindikationen:
const obj: {[key: string]: string} = {};
Kom dock ihåg att det inte kommer att kontrollera om en nyckel finns.
Så att kompilatorn kommer att tro det
const exists = obj["a"];
const doesntExists = obj["junk"];
är okej. Du måste fortfarande kontrollera efter odefinierade värden.
