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

Logical and loses narrowed types when testing for truthyness on union types #29106

Closed
asmundg opened this issue Dec 20, 2018 · 1 comment
Closed
Assignees
Labels
Bug A bug in TypeScript

Comments

@asmundg
Copy link
Member

asmundg commented Dec 20, 2018

TypeScript Version: 3.3.0-dev.20181220

Search Terms: narrow union regression

Code

const f = (_a: string, _b: string): void => {};

interface A {
  a?: string;
  b?: string;
}

interface B {
  a: string;
  b: string;
}

type U = A | B;

const u: U = {} as any;

// u.b narrowed, but not a
// Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
//   Type 'undefined' is not assignable to type 'string'.
u.a && u.b && f(u.a, u.b);

// Error: u.a narrowed, but not b
// Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
//   Type 'undefined' is not assignable to type 'string'.
u.b && u.a && f(u.a, u.b);

// Works
typeof u.a === "string" && typeof u.b === "string" && f(u.a, u.b);

// Works
const a: A = {} as any;
a.b && a.a && f(a.a, a.b);

Expected behavior:

All forms narrow correctly and compile with strictNullChecks.

This works correctly in 3.1.6

Actual behavior:

Only non-union or explicitly checking typeof narrows correctly in >=3.2.

Playground Link: (Needs strictNullChecks enabled) http://www.typescriptlang.org/play/#src=const%20f%20%3D%20(_a%3A%20string%2C%20_b%3A%20string)%3A%20void%20%3D%3E%20%7B%7D%3B%0D%0A%0D%0Ainterface%20A%20%7B%0D%0A%20%20a%3F%3A%20string%3B%0D%0A%20%20b%3F%3A%20string%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20B%20%7B%0D%0A%20%20a%3A%20string%3B%0D%0A%20%20b%3A%20string%3B%0D%0A%7D%0D%0A%0D%0Atype%20U%20%3D%20A%20%7C%20B%3B%0D%0A%0D%0Aconst%20u%3A%20U%20%3D%20%7B%7D%20as%20any%3B%0D%0A%0D%0A%2F%2F%20u.b%20narrowed%2C%20but%20not%20a%0D%0A%2F%2F%20Argument%20of%20type%20'string%20%7C%20undefined'%20is%20not%20assignable%20to%20parameter%20of%20type%20'string'.%0D%0A%2F%2F%20%20%20Type%20'undefined'%20is%20not%20assignable%20to%20type%20'string'.%0D%0Au.a%20%26%26%20u.b%20%26%26%20f(u.a%2C%20u.b)%3B%0D%0A%0D%0A%2F%2F%20Error%3A%20u.a%20narrowed%2C%20but%20not%20b%0D%0A%2F%2F%20Argument%20of%20type%20'string%20%7C%20undefined'%20is%20not%20assignable%20to%20parameter%20of%20type%20'string'.%0D%0A%2F%2F%20%20%20Type%20'undefined'%20is%20not%20assignable%20to%20type%20'string'.%0D%0Au.b%20%26%26%20u.a%20%26%26%20f(u.a%2C%20u.b)%3B%0D%0A%0D%0A%2F%2F%20Works%0D%0Atypeof%20u.a%20%3D%3D%3D%20%22string%22%20%26%26%20typeof%20u.b%20%3D%3D%3D%20%22string%22%20%26%26%20f(u.a%2C%20u.b)%3B%0D%0A%0D%0A%2F%2F%20Works%0D%0Aconst%20a%3A%20A%20%3D%20%7B%7D%20as%20any%3B%0D%0Aa.b%20%26%26%20a.a%20%26%26%20f(a.a%2C%20a.b)%3B%0D%0A

Related Issues:

#29012

@ahejlsberg
Copy link
Member

I'm pretty sure this is caused by #27695. The compiler ends up considering a and b discriminant properties and that in turn causes us to more aggressively reset other narrowing assumptions during control flow analysis.

@ahejlsberg ahejlsberg self-assigned this Dec 20, 2018
@ahejlsberg ahejlsberg added the Bug A bug in TypeScript label Dec 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants