funktionell programmering - Varför härleder TypeScript typen 'never' när man reducerar en Array med concat?


Kod talar bättre än språk, så:

['a', 'b', 'c'].reduce((accumulator, value) => accumulator.concat(value), []);

Koden är väldigt fånig och returnerar en kopierad array...

TS klagar på concat's argument: TS2345: Argument av typen 'string' kan inte tilldelas parametern av typen 'ConcatArray'.

Svar #1

Jag tror att detta beror på att typen för [] antas vara never[], vilket är typen för en array som MÅSTE vara tom. Du kan använda en typomvandling för att åtgärda detta:

['a', 'b', 'c'].reduce((accumulator, value) => accumulator.concat(value), [] as string[]);

Normalt skulle detta inte vara något större problem eftersom TypeScript gör ett ganska bra jobb med att lista ut en bättre typ att tilldela en tom array baserat på vad du gör med den. Men eftersom ditt exempel är 'löjligt' som du uttryckte det, kan TypeScript inte göra några slutledningar och lämnar typen som never[].

Svar #2

En bättre lösning som undviker en typavstämning (även kallad typomvandling) i två varianter:

  1. Använd string[] som den generiska typparametern för reduce-metoden (tack @depoulo för att du nämnde det):
['a', 'b', 'c'].reduce<string[]>((accumulator, value) => accumulator.concat(value), []);
  1. Skriv in accumulator-värdet som string[] (och undvik en typkonvertering på []):
['a', 'b', 'c'].reduce((accumulator: string[], value) => accumulator.concat(value), []);

Lek med denna lösning i TypeScript-lekplatsen.

Anteckningar:

  1. Typpåståenden (ibland kallade typomvandlingar) borde undvikas om du kan eftersom du tar en typ och överför den på något annat. Detta kan orsaka bieffekter eftersom du manuellt tar kontroll över att tvinga en variabel till en annan typ.

  2. Detta Typescript-fel uppstår endast om strictNullChecks-alternativet är inställt på true. Typescript-felet försvinner när du stänger av det alternativet, men det är förmodligen inte vad du vill.

  3. Jag refererar till hela felmeddelandet jag får med Typescript 3.9.2 här så att Google hittar denna tråd för personer som söker svar (eftersom Typescript-felmeddelanden ibland ändras från version till version):

    No overload matches this call.
      Overload 1 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
     Argument of type 'string' is not assignable to parameter of type 'ConcatArray<never>'.
      Overload 2 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
     Argument of type 'string' is not assignable to parameter of type 'ConcatArray<never>'.(2769)
    

Relaterade artiklar