Hur man får funktioner att behandla returvärdet av (A | B)[] och A[] | B[] som ekvivalent i TypeScript


Det verkar som att typerna (A | B)[] och A[] | B[] är ekvivalenta i TypeScript. Detta kan bekräftas genom följande:

var test1: number[] | string[] = [1]
var test2: (number | string)[] = ["stuff"]
var test3: (number | string)[] = test1

Men det verkar som att detta faller isär när dessa typer dyker upp i returfunktioner. Detta illustreras nedan:

function getStuff(flag:number): number | string {
    if (flag == 0) {
        return 1
    } else {
        return "hello"
    }
}

function returnStuff(flag: number): number[] | string[] {
    let toReturn: (number | string)[] = [getStuff(flag)]
    // toReturn is of type (number | string)[] but trying to return it when the return type
    // is number[] | string[] fails even though they should be equivalent
    return toReturn;
}

Jag har då två frågor:

  1. Vad är anledningen till detta beteende och hur kan det åtgärdas för att få önskat beteende?
  2. Finns det någon typnivåmaskineri i TS som kan användas för att konvertera mellan number[] | string[] och (number | string)[]

Svar #1

Vad är orsaken bakom detta beteende

nummer[] | sträng[]

du har två möjliga arrayer, en array som endast innehåller siffror, och en array som endast innehåller strängar

[1,2,3,4] //valid  
["foo", "bar"] //valid  
[1,2,"foobar"] //this is invalid

(nummer | sträng)[]

Du har en möjlig array som innehåller antingen ett nummer eller en sträng.

[1,2,3,4] //valid  
["foo", "bar"] //valid  
[1,2,"foobar",3,"lorem"] //valid

I den här är den viktigaste punkten att komma ihåg att arrayen kan innehålla ett element som är av typen sträng ELLER nummer, oavsett om alla element i arrayen är av samma typ eller inte

Finns det någon typnivåmaskineri i TS som kan användas för att konvertera mellan number[] | string[] och (number | string)[]

Du kan fortfarande använda din string[] eller number[] som (string | number)[]

let x: number[] = [1,2,3,4]

return x as (number | string)[]