Home > Back-end >  Why does TypeScript not report a "wrong" function return type
Why does TypeScript not report a "wrong" function return type

Time:09-30

I'm surprised why TypeScript 4.4.3 would not report an invalid type for the callback function? This seems reasonable when returning a "non-promise" type but when returning a Promise it seems likely that we must wait for it to resolve. setCallback expects a function returning void but is invoked with a function returning Promise<void> indicates that there is something to wait for.

const setCallback = (cb: () => void): void => {
    cb();
};

const callback = (): Promise<void> => {
    return new Promise(resolve => {
        setTimeout(() => resolve(), 100);
    });
}

setCallback(callback);

TS Playground

CodePudding user response:

TypeScript doesn't care

You only give a function reference to setCallback() which can be anything you like. As long as you don't invoke the function itself, it counts as an object and TypeScript won't give you a TypeError since your function is expecting an object.

If you were to call the object, it would turn into it's respective type for which TypeScript does give you a TypeError in case of a mismatch.

  1. Variables passed by reference

In Pass by Reference, a function is called by directly passing the reference/address of the variable as the argument. Changing the argument inside the function affects the variable passed from outside the function. In Javascript objects and arrays are passed by reference.

  1. Functions (MDN)

Generally speaking, a function is a "subprogram" that can be called by code external (or internal in the case of recursion) to the function. Like the program itself, a function is composed of a sequence of statements called the function body. Values can be passed to a function, and the function will return a value.

In JavaScript, functions are first-class objects, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are Function objects.

Example 1

Since I cannot use .then() on void functions, I had to create an IIFE to make it async and it still works even though I'm expecting a void type callback.

const setCallback = (cb: () => void): void => {
    (async () => await cb())().then(() => console.log("Hi"));
};

const callback = (): Promise<number> => {
    return new Promise(resolve => {
        setTimeout(() => resolve(0), 100);
    });
}

setCallback(callback);

Example 2

If you try to invoke it with a Promise return type:

Argument of type 'Promise' is not assignable to parameter of type '() => void'. Type 'Promise' provides no match for the signature '(): void'.

The error refers to the mismatch of Function signatures.

const setCallback = (cb: () => void): void => {
    (async () => await cb())().then(() => console.log("Hi"));
};

const callback = (): Promise<number> => {
    return new Promise(resolve => {
        setTimeout(() => resolve(0), 100);
    });
}

setCallback(callback());
  • Related