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

Type predicate for an optional property is not inferred #59494

Open
amakhrov opened this issue Jul 31, 2024 · 5 comments
Open

Type predicate for an optional property is not inferred #59494

amakhrov opened this issue Jul 31, 2024 · 5 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@amakhrov
Copy link

amakhrov commented Jul 31, 2024

πŸ”Ž Search Terms

inferred type predicate optional

πŸ•— Version & Regression Information

  • This changed between versions 5.4 and 5.5

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.5.4#code/C4TwDgpgBA8gRgKygXigbwPZmASwwOwEMAbAfgC51DL8BXAWzggCcBfVgKFElkQCYU6LLgIkKUWvgAmEAGY58EKaygAfIdjxFilNNSh1GLdh1OzJAYxH4oOAM4xNo4gBE5CpQAoIleAgCU6BwA9MFQ4RFQAHqkHJHMEMC0zDYQAHTCWiRQAITIqJIy8opSHJwc5vhWWrYOTtpuxUp83r78gWghYTFxEQlJKVDpmc65+RLS7iVlHEA

πŸ’» Code

type Obj = {optional?: {a: number}}

function isOptionalDefined(e: Obj) {
    return e.optional !== undefined
}

if (isOptionalDefined(someObj) {
  someObj.optional.a // 'someObj.optional' is possibly 'undefined'
}

πŸ™ Actual behavior

If a type contains an optional property, and I write a function that ensures the property is defined, the function is not inferred as a type predicate. No type narrowing happens when I use this function.

At the same time, if I rewrite the original type to be itself a union, then the type predicate is inferred, as expected.

πŸ™‚ Expected behavior

Type predicate is inferred

Additional information about the issue

I feel it has something to do with #55257, but I'm not sure.

@Andarist
Copy link
Contributor

Andarist commented Aug 1, 2024

This isn't specific to optional properties:

type Obj = { prop: string | number };

function hasNumberProp(e: Obj) {
  //     ^? function hasNumberProp(e: Obj): boolean
  return typeof e.prop === "number";

See #59088 (comment)

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature labels Aug 1, 2024
@amakhrov
Copy link
Author

amakhrov commented Aug 1, 2024

Indeed, not specific to optional.
Anyway, having an inline if check would practically (from the usage standpoint) narrow it down - meaning I can access e.optional without a TS error:

if (e.optional) {
  e.optional.a // OK!
}

@Andarist
Copy link
Contributor

Andarist commented Aug 1, 2024

The gained knowledge is only about properties, it doesn't propagate to the containing object type:

type Obj = { optional?: { a: number } };

function takeRequired(e: { optional: { a: number } }) {}

function test(e: Obj) {
  if (e.optional) {
    e.optional.a; // OK!
    takeRequired(e); // not OK!
  }
}

That's a current design limitation that is not exclusive to type predicates.

@miguel-leon
Copy link

miguel-leon commented Aug 12, 2024

If this worked, it would be really useful for String.matchAll result (RegExpExecArray) with regexp with capturing groups.
Please let us know if the feature is not intended to be this capable.
I understand it's not possible because design limitation, right?

@yukimotochern
Copy link

Would be great if this works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants