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

Equality operator with unknown does not narrow the type of the unknown #25172

Closed
MadaraUchiha opened this issue Jun 23, 2018 · 8 comments
Closed
Labels
Committed The team has roadmapped this issue Help Wanted You can do this Suggestion An idea for TypeScript

Comments

@MadaraUchiha
Copy link

TypeScript Version: 3.0.0-dev.20180623

Search Terms: typescript unknown equality guard

Code

let x: unknown; // reproduces with const too
if (x === 5) {
    let y = x.toString(10);
}

Expected behavior:
x inside of the if block to be of type 5, y to get type of string, everyone happy.
Actual behavior:
x inside of the if block is still of type unknown, I get an error for x being of type unknown and therefore does not have a property toString.
Playground Link: N/A (dev build)

Related Issues: #24439

@jcalz
Copy link
Contributor

jcalz commented Jun 23, 2018

Related to #9999 also?

@MadaraUchiha
Copy link
Author

@jcalz Not exactly, that there is a feature request, unknown can be narrowed in other ways. The following is the result on the TypeScript version mentioned at the top of this issue:

let x: unknown; // unknown always considered initialized.
if (Array.isArray(x)) {
    x; // any[] (I would expect unknown[], but that's a different issue)
} else if (x instanceof Promise) {
    x; // Promise<any> (again, would expect Promise<unknown> but eh)
} else if (x === true) {
    x; // unknown, wat.
}
let y = String(x); // y: string, as expected
let z = Number(x); // z: number, as expected

So you see, the only real "wat" here is the direct equality comparison.

It's also worth noting that this behavior is consistent with any (That is, attempts to narrow any with equality are met with any as the narrowed type), but this is still rather unexpected behavior.

@DanielRosenwasser DanielRosenwasser added the Bug A bug in TypeScript label Jun 23, 2018
@DanielRosenwasser DanielRosenwasser added this to the TypeScript 3.0 milestone Jun 23, 2018
@weswigham
Copy link
Member

weswigham commented Jun 25, 2018

@DanielRosenwasser === today doesn't narrow anything other than members from unions or primitives into literals today. unknown is neither a primitive nor a union, so this is expected under our current rules, just like how {} and any won't be narrowed by ===, either.

@mhegazy mhegazy added Suggestion An idea for TypeScript and removed Bug A bug in TypeScript labels Jun 25, 2018
@mhegazy mhegazy removed this from the TypeScript 3.0 milestone Jun 25, 2018
@mhegazy mhegazy added the In Discussion Not yet reached consensus label Jun 25, 2018
@JacksonKearl
Copy link

This is especially helpful for narrowing unknown to a string enum

type Response = 'yes' | 'no' | 'idk';
let validate: (x: unknown) => Response = x => (x === 'yes' || x === 'no') ? x : 'idk'; // Err: type 'unknown' is not assignable to type '"idk"'

@mhegazy
Copy link
Contributor

mhegazy commented Jul 27, 2018

Similar requests in #10715, #25720, and #21732

@RyanCavanaugh
Copy link
Member

Accepting PRs assuming there isn't any big impact to perf or complexity

@jack-williams
Copy link
Collaborator

Attempt at a PR up at #26941

@cnshenj
Copy link

cnshenj commented Jan 29, 2019

Question: why just unknown, shouldn't any work the same way?

--strict
let a: any = Math.random();
if (a === null) {
    // a is null type, not any type
}

RyanCavanaugh added a commit that referenced this issue Jan 30, 2019
…le-equals

Fix #25172: Add narrowing for `unknown` with triple equals
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Committed The team has roadmapped this issue Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

9 participants