3

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 ?

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.