-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Negated instanceof check doesn't seem to narrow the types correctly in an edge case #56673
Comments
|
I suspect it's a bit more complicated than that. That's because with this locally defined class TS narrows the types the way I'd expect it to while the conditions are the same: class Whatever {}
function f(value: Whatever | string) {
if (value instanceof Whatever) {
// value is Whatever
console.log(value)
}
if (!(value instanceof Whatever)) {
// vale is string
console.log(value)
}
} |
Huh, that's interesting; IIRC the compiler devs have explicitly said in the past that |
Yup, agreed. Thank you for the background information. |
Worth pointing out that class Whatever { val: string = 'abc' }
function f(value: Whatever | string) {
if (value instanceof Whatever) {
console.log(value.val);
}
if (!(value instanceof Whatever)) {
console.log(value.charAt(0));
}
}
f({ val: 'foo' }) |
Ugh, I managed to forget about this aspect of |
A minimal inlined definition of |
It’s not really a problem with |
Yeah, what I meant to say: I forget that classes/class instances participate in the same structural typing mechanism as other types, it always trips me as I expect them not to. @RyanCavanaugh if by "inline" you mean "in the same file" then I made several attempts and failed. This snippet, for example, which is as close to the original big.js type definitions as possible and rather minimal doesn't exhibit the problem: namespace ExternalModule {
namespace Big {
export interface BigConstructor {
new(value: string): Big;
(value: string): Big;
(): BigConstructor;
readonly Big: BigConstructor;
}
export interface Big {
abs(): Big;
}
}
export declare const Big: Big.BigConstructor;
export type Big = Big.Big;
}
function f(value: ExternalModule.Big | string) {
if (value instanceof ExternalModule.Big) {
// value is Big
console.log(value);
}
if (!(value instanceof ExternalModule.Big)) {
// value is string, works correctly :|
console.log(value);
}
} I tried to get as close to big.js' declare const Big: Big.BigConstructor;
type Big = Big.Big;
// The export is the same as type/value combo symbol 'Big'.
export = Big;
export as namespace Big; I had to settle for export declare const Big: Big.BigConstructor;
export type Big = Big.Big; because I don't think the I suspect these error statements are causing the problem. Any tips for reproducing this inline? I'm out of ideas. |
I ran out of ideas and am unable to reproduce this inline, using just a single file. I'm afraid I give up. |
Hey @RyanCavanaugh, may I ask if we should interpret "closed this as completed" as "working as intended/won't fix"? |
Closing because we need a repro that doesn't depend on a large dependency in order to investigate and one was not provided |
Got it, appreciate the clarification. |
🔎 Search Terms
instanceof narrowing
instanceof negation
narrowing negation
negative type narrowing
big.js
🕗 Version & Regression Information
⏯ Playground Link
https://codesandbox.io/s/typescript-playground-export-forked-78znfm?file=%2Findex.ts
💻 Code
Dependencies (
package.json
):🙁 Actual behavior
Inside the
if (!(value instanceof Big))
block the type ofvalue
is not narrowed toBig
, it remainsBig | string
🙂 Expected behavior
Inside the
if (!(value instanceof Big))
block I expect the type ofvalue
to be narrowed to not beBig
, so:string
.The
if (value instanceof Big)
condition does narrowBig | string
toBig
so I'd expect the opposite condition to do the opposite.Additional information about the issue
The issue is present with
@types/big.js
6.2+.It's not present with
@types/big.js
6.1.0.I've been unable to artificially reproduce this issue using a single source file without referring to the big.js type definitions.
As far as I can tell it's introduced in this DefinitelyTyped change: DefinitelyTyped/DefinitelyTyped#66163 (which is a response to a bug report here, #50058 (comment))
cc @andrewbranch this may interest you
I didn't know if I should report this to TS or the DT project, I went with TS.
The text was updated successfully, but these errors were encountered: