Skip to content

Compatibility error when callback has void return type #38284

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sosuisen opened this issue May 1, 2020 · 4 comments
Closed

Compatibility error when callback has void return type #38284

sosuisen opened this issue May 1, 2020 · 4 comments

Comments

@sosuisen
Copy link

sosuisen commented May 1, 2020

TypeScript Version: 3.8.3

Search Terms:
callback return type void

Code

const a: () => number = (): void => {};  // Type error. It is expected.
const b: () => void = (): number => { return 7 };  // Ok. It is expected.

a and b are expected behaviors which have been discussed many times,
see #21674 (comment)

But the following examples are different.

const f: (x: () => number) => number = (y: () => void) => 7;  // Ok. It is expected.
const g: (x: () => void) => number = (y: () => 7) => 7; // Type error. It is not expected. It should be Ok.

According to the Assignment Compatibility,
f is also expected behavior, that is to say,
type '(() => void) => number' is assignable to '(() => number) => number'
because both types are object (function) type
and the parameter type in '(() => void) => number' is assignable to or from the corresponding parameter type in '(() => number) => number'.

Here, parameter type '() => void' is assignable from type '() => number'.

g is expected to be ok because parameter type '() => number' is assignable to type '() => void',
according to Assignment Compatibility which says that 'each parameter type in N is assignable to or from the corresponding parameter type in M'.

Expected behavior:
Assignment Compatibility document may be wrong or its implementation may be wrong.

I assume that both may be wrong, f should be type error and g should be Ok in the same way as a and b.

@MartinJohns
Copy link
Contributor

This is working as intended.

Why are functions returning non-void assignable to function returning void?

Assignment Compatibility document may be wrong or its implementation may be wrong.

The specification is not maintained and heavily outdated. You should not use it to verify any behavior of TypeScript. It was last updated in early 2016. See #15711.

@sosuisen
Copy link
Author

sosuisen commented May 1, 2020

I have already read the FAQ many times, but the FAQ explains only a and b.

The FAQ shows f is type error and g is OK, however the actual behavior is that f is ok and g is type error.

const f: (x: () => number) => number = (y: () => void) => 7;  // Ok in the actual behavior
const g: (x: () => void) => number = (y: () => 7) => 7; // Type error in the actual behavior

@nmain
Copy link

nmain commented May 1, 2020

The variance flips when a parameter appears as an input to a function. Easiest to understand this by trying an example that would fail if the types are wrong:

const gimpl = (y: () => 7) => {
    const ret = y();
    if (ret !== 7) {
        throw new Error("Type was not expected")
    }
    return ret;
}

const g: (x: () => void) => number = gimpl;

g(() => { console.log("this function doesn't return anything") });

Playground Link

@sosuisen
Copy link
Author

sosuisen commented May 1, 2020

The variance flips when a parameter appears as an input to a function. Easiest to understand this by trying an example that would fail if the types are wrong:

I got it. Thanks for the easy to understand example.

@sosuisen sosuisen closed this as completed May 1, 2020
sosuisen added a commit to sosuisen/shibungi-tstest-voidtype that referenced this issue May 6, 2020
Updated annotations by using current knowledge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants