javascript - Er det mulig å bruke Array.prototype.map() på en tuple i TypeScript samtidig som tuple-lengden bevares i returtypen?
Jeg hadde håpet at hvis jeg bruker den innebygde map-funksjonen på en tuple med lengde N i TypeScript, så ville returtypen også være en tuple med lengde N (kanskje med en annen type for elementene avhengig av funksjonen som sendes til map). I stedet er returtypen bare et standard, variabel-lengde array av hvilken som helst type callback-funksjonen returnerer. Tuple-lengden går tapt. Jeg skrev en egen funksjon som gjør det jeg ønsker, men jeg lurer på om det finnes en bedre måte som jeg overser. Jeg prøver å forbedre forståelsen min av TypeScript. Jeg har inkludert en TypeScript Playground-lenke under koden (med samme kode). Takk for hjelpen!
const nums = [1, 2, 3] as const;
// result1 type is string[]
const result1 = nums.map((num) => num.toString());
// so this won't compile
const result2: [string, string, string] = nums.map((num) => num.toString());
// a type assertion would work, but I'd rather not use one...
const result3 = nums.map((num) => num.toString()) as [string, string, string];
// ...because this also compiles yet the type of result4 doesn't match its value
const result4 = nums.map((num) => num.toString()) as [string, boolean, number, symbol, string, number];
// result5 type is [string, string, string]
const result5 = map(nums, (num) => num.toString());
// custom map function that yields the correct return type when used on a tuple
function map<A extends readonly [...any[]], B>(values: A, func: (value: A[number]) => B): { [K in keyof A]: B } {
return values.map(func) as unknown as { [K in keyof A]: B };
}
Se på: TypeScript-lekeplass
Svar #1
Vennligst prøv neste:
type A = readonly [1, 2, 3]
const nums: A = [1, 2, 3];
const toStr = <T extends number>(num: T) => num.toString() as `${T}`
const result2 = nums.map(toStr); // ("3" | "1" | "2")[]
Jeg tror dette ikke er den beste løsningen, fordi du fortsatt har ('3'|'2'|'1')[] og ikke ['1','2','3'], men dette er et slags fremskritt
Jeg vil være glad for å se andre løsninger her. Veldig interessant problem )
Fungerer kun med T.S 4.1
OPPDATERING
Det er en mulighet til å lage typen du ønsker med litt hjelp av overbelastning og variadiske tuplet-typer
type Json =
| string
| number
| boolean
| { [prop: string]: Json }
| Array<Json>
type CustomMap<T extends ReadonlyArray<Json>> = {
[Index in keyof T]: { elem: T[Index] }
}
function map<Elem extends Json, List extends Elem[], Return>(list: [...List], callback: (value: Elem) => Return): CustomMap<List>
function map<Elem extends Json>(list: Elem[], callback: (elem: Elem) => unknown) {
return list.map(callback)
}
// const result2: [{
// elem: 1;
// }, {
// elem: 2;
// }, {
// elem: 3;
// }]
const result2 = map([1, 2, 3], elem => ({ elem }));
Lekeplass
