Skip to content
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

Can create variable of type never from function returning void by using typeof #54032

Closed
tyilo opened this issue Apr 26, 2023 · 7 comments
Closed
Labels
Duplicate An existing issue was already created

Comments

@tyilo
Copy link

tyilo commented Apr 26, 2023

Bug Report

It is possible to create a variable with type never from a function returning void, by narrowing it's return value using typeof.

This should not be possible.

🔎 Search Terms

never, void, typeof

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about void

⏯ Playground Link

Playground link with relevant code

💻 Code

function f(x: never): void {
    console.log("Called function that should be uncallable:", x);
}

const g: () => void = () => "123";
const v = g();
if (typeof v === "string") {
    f(v);
}

🙁 Actual behavior

The code successfully type checks and f is called when running even though it has a never parameter.

🙂 Expected behavior

The code should not type check as v should be inferred to have type string and not never inside the if-body.

Alternatively, typeof v should not be allowed when v has type void.

@fatcerberus
Copy link

fatcerberus commented Apr 26, 2023

This is like the dual of the situation where someone writes string | void and then tries to narrow it using typeof x === 'string', which is just as unsound (you'll definitely get a string, but it might be garbage). I've been saying this for years, void is not a synonym for undefined and shouldn't be treated as such, but the compiler itself is inconsistent about it. See also #42709.

The code should not type check as v should be inferred to have type string and not never inside the if-body.

For the record, v should properly have the type void inside the if block; it should not be narrowed at all. It shouldn't narrow to string there because any value you get would be garbage by definition.

@RyanCavanaugh RyanCavanaugh added Duplicate An existing issue was already created and removed Duplicate An existing issue was already created labels Apr 26, 2023
@RyanCavanaugh
Copy link
Member

I don't think this is fixable, except via #42709, without introducing new problems.

People (because we haven't cracked the nut on #42709) write

const x: string | void = someFuncOrSomeOtherFunc();
if (typeof x === "string") {
// or
if (x !== undefined) {
  doSomethingWithString(x);
}

Basically for narrowing purposes, void is treated as undefined, so a narrowing to string -> string & undefined -> never. We could make this asymmetrical but it just changes the shape of the problem rather than removing it.

Narrowing being fully symmetrical is critical since any narrowing needs to be undoable via unioning of both parts, since this is how CFA works. Otherwise you run into problems where you write

const x = someExpr();
x; // <- point a
if (narrowing on x) { /* no-op */ }
x; // <- point b

x will have different types at point a and b if you're not careful about what narrowing does to x

@fatcerberus
Copy link

FWIW people really shouldn't be writing const x: string | void = someFuncOrSomeOtherFunc(); and then trying to narrow it in the first place - by definition the void side of the union is inhabited by all possible values, and all are garbage (because void is a promise that the caller won't touch the return value).

@microsoft-github-policy-service

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

1 similar comment
@microsoft-github-policy-service

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@tyilo
Copy link
Author

tyilo commented Apr 28, 2023

I don't see why this is a duplicate (of #42709 ?).

Fixing #42709 might also fix this, but it seems like this issue can be fixed without fixing #42709.

@tyilo
Copy link
Author

tyilo commented Apr 28, 2023

#42709 doesn't mention the never type either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants