javascript - TypeScript array.sort() av typade värden
Låt oss anta att vi har en typ och en array:
type Fruit = 'apple' | 'orange' | 'pineapple'
const initialFruits: Fruit[] = ['pineapple', 'apple', 'orange']
Om jag försöker sortera arrayen innan jag tilldelar värdet får jag ett fel:
const initialFruits: Fruit[] = ['pineapple', 'apple', 'orange'].sort()
// Type 'string[]' is not assignable to type 'Fruit[]'.
Jag hittade ett sätt att spara typer efter sortering, men det ser konstigt ut:
const initialFruits: Fruit[] = [
'pineapple' as const,
'apple' as const,
'orange' as const
].sort()
Finns det ett mer bekvämt sätt att fixa det?
Svar #1
Om du vill att din kod ska vara typ-säker utan att ändra körningens beteende (t.ex. utan att kalla på sort() i en separat sats), skulle mitt förslag vara att använda satisfies-operatorn för att ge kompilatorn kontext att array-litteralen ['pineapple', 'apple', 'orange'] kommer att behandlas som en Fruit[]. På detta sätt:
const initialFruits =
(['pineapple', 'apple', 'orange'] satisfies Fruit[]).sort()
Det kompilerar. ['pineapple', 'apple', 'orange'] satisfies Fruit[] resulterar i ett uttryck av typen ("apple" | "orange" | "pineapple")[] (vilket är ekvivalent med Fruit[] men skulle inte vara det om du till exempel skrev ['apple', 'orange'] satisfies Fruit[], där du skulle få ett värde av typen ("apple" | "orange")[]). Och så har du fortfarande en förändringsbar arraytyp, som är känd för att ha en sort()-metod. Så du får:
initialFruits
//^? const initialFruits: ("apple" | "orange" | "pineapple")[]
vilket borde fungera för dig.
Observera att detta är en starkare garanti för typssäkerhet än att använda en typkonvertering som as Fruit[]. Jämför:
(['pineapple', 'apple', 'cherry'] satisfies Fruit[]).sort(); // error!
// -------------------> ~~~~~~~~
// Type '"cherry"' is not assignable to type 'Fruit'.
(['pineapple', 'apple', 'cherry'] as Fruit[]).sort(); // no error!
Playground-länk till kod
Svar #2
Arrayen är sorterad enligt Fruit-typ.
type Fruit = 'apple' | 'orange' | 'pineapple'
const initialFruits: Fruit[] = ['pineapple', 'apple', 'orange'].sort() as Fruit[];
const sortedFruits: Fruit[] = ['pineapple', 'apple', 'orange'].sort((a, b) => {
return initialFruits.indexOf(a) - initialFruits.indexOf(b);
}) as Fruit[];
