Home > other >  TypeScript infer about array[index]
TypeScript infer about array[index]

Time:07-28

I expected result is number | never[]. But actually number | never[] | undefined.

type T1 = (number | undefined)[]

const myFunc = (arr: T1, index: number) => {
    const result = arr[index] === undefined ? [] : arr[index]
    return result // number | never[] | undefined
}

Why does it behave like this ?

CodePudding user response:

Looks like TypeScript needs some help to infer types correctly based on your ternary expression. You can fix it in two ways:

Introduce a variable

const myFunc = (arr: T1, index: number) => {
    const value = arr[index];
    const result = value === undefined ? [] : value;
    return result // number | never[]
}

Use the non-null assertion operator to help the compiler understand that the value will never be undefined:

const myFunc = (arr: T1, index: number) => {
    const result = arr[index] === undefined ? [] : arr[index]!
    return result // number | never[]
}

CodePudding user response:

TypeScript uses flow analysis to narrow down types of variables. However, it seems unable to narrow down arr just by checking that one of the elements is undefined:

type T1 = (number | undefined)[]
const myFunc = (arr: T1, index: number) => {
    if (arr[index] === undefined) {
        return []; // never[]
    }
    //the type of `arr` is still considered T1
    let temp = arr[index]; //number | undefined 
    return temp;
}

Actually, I'm not sure how else should the type of arr be represented as after the if block (how would you represent "an array of number|undefined, except that this particular dynamic index is not undefined"?). It still makes some sense to simply fall back to T1.

Your code uses ternary operator, but it acts similarly to my code above.

However, TypeScript can narrow down the types for a result variable when the variable is used in a direct comparison in a flow control statement:

type T1 = (number | undefined)[]
const myFunc = (arr: T1, index: number) => {
    const result = arr[index];
    if (result === undefined) {
        return []; // never[]
    }
    //the type of `result` is correctly determined as number, not undefined
    return result;
}

I think arr and result (variables) may have their types narrowed down by control flow, but arr[index] (an expression, not just a variable) will just be computed from the types of arr and index at that point.

  • Related