Home > front end >  Why is TypeScript expecting arguments for a function defined with no arguments that is returned in a
Why is TypeScript expecting arguments for a function defined with no arguments that is returned in a

Time:05-21

I am learning TypeScript. Just created this simple function and executed it. But I don't understand why does the compiler show the error in the below code. Please refer to the screenshot for the error.

function makePair<T, S> () {
    let pair: { first: T, second: S}
    function getPair() {
        return pair
    }
    function setPair(x: T, y: S) {
        pair = {
            first: x, second: y
        }
    }
    return [ getPair, setPair ];
}

const [ getPair, setPair ] = makePair<number, boolean>();
setPair(121, true);
console.log(getPair())  

Error screenshot here

CodePudding user response:

Problem (presumed)

Starting off with a caveat that this is what I presume the problem to be because my understanding of TypeScript isn't extremely deep. This explanation may not be totally correct or may not be elaborated well.

Your function is declared without an explicit return type:

function makePair<T, S> () { ... }

As a result, TypeScript will attempt to infer the return type from the expression returned:

return [ getPair, setPair ];
//     ^^^^^^^^^^^^^^^^^^^^
//    The expression returned

You may think the expression's type is supposed to be inferred to:

[() => { first: T, second: S }, (x: T, y: S) => void]

However this doesn't happen. It actually got inferred to:

((x: T, y: S) => void)[]

As arrays are mutable, TypeScript cannot guarantee your type will always be [() => { first: T, second: S }, (x: T, y: S) => void]. It therefore widens the type to ((x: T, y: S) => void)[]. (Although why it widened it to that, I'm not certain and it could be a bug).

Solution

You'll need to explicitly type your return type. Examples:

function makePair<T, S> (): [() => { first: T, second: S }, (x: T, y: S) => void] {

    // ...

    return [ getPair, setPair ];
}

TypeScript Playground

function makePair<T, S> () {

    // ...

    return [ getPair, setPair ] as [typeof getPair, typeof setPair];
}

TypeScript Playground

Or make a const assertion to force the compiler to not widen types:

function makePair<T, S> () {

    // ...

    return [ getPair, setPair ] as const;
}

TypeScript Playground

Further reading

CodePudding user response:

TypeScript has strict type check features, meaning that if you define some variable of a certain type, it will expect you to pass that type of values only to the variable. Like in your case, while declaring the getPair function in:

const [ getPair, setPair ] = makePair<number, boolean>();

you have declared getPair function of type makePair to expect a number and boolean parameters, which you did not provide while calling it in console.log(getPair()) resulting in it showing error.

  • Related