microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

Home Page:https://www.typescriptlang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Narrowing by type predicate fails to produce intersection type with weak type

danvk opened this issue Β· comments

πŸ”Ž Search Terms

  • predicate
  • intersection
  • weak

πŸ•— Version & Regression Information

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

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.5.0-beta&ssl=7&ssc=20&pln=7&pc=21#code/JYOwLgpgTgZghgYwgAgILIN4ChnIDZwBGEeA-AFzIDOYUoA5gNw7JwXW0OO4D0PyAWzgBrFFAgBHAK7BxAE2RgA9shLABoOJFVQoSqFgC+WLKEixEKAEKYWBYmUo06IJr37iBSgG4oqACzh5ZAAHPRDoMABPRRU1DRAtFGg9A1xCSkIlJTwIOBBmYywYKRAEMGAlEGRgKisACjB-BkolQgArCHKASkomhhqqZBtsXHEwKShqgHJCaZrq-tdCkxKyiqrFCBpG5tdKVG7bXCX6ADo4bmQ+ZCVhFmAYZHrahtPuo9HcRT3zy-cdKlSCxjMYgA

πŸ’» Code

interface A {
  label?: string;
  a?: string;  // make required to eliminate error
}

interface B {
  label?: string;  // remove shared property to eliminate error
  b: boolean;
}

function isB(thing: object): thing is B {
  return 'b' in thing;
}

function test(thing: A) {
  thing.a;  // ok
  if (isB(thing)) {
    thing.a;  // error?
  }
}

πŸ™ Actual behavior

The type of thing inside the conditional is B.

πŸ™‚ Expected behavior

The type of thing inside the conditional should be A & B.

Additional information about the issue

This only happens if:

  1. A is a "weak" type (all optional properties).
  2. A and B have at least one overlapping property.

If either of these isn't the case, then you get the expected intersection type:
image

This came up in vscode while testing #58495 (comment). The issue is there already but is latent because control flow analysis can't see that a type predicate becomes a type assertion without that PR.

https://github.com/microsoft/vscode/blob/273d65a156865def7869e2899235ea2ab9837a81/src/vs/workbench/api/common/extHostTreeViews.ts#L821