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[];

Relaterade artiklar