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

TS 5.5 type guards overly strict in some cases #58959

Closed
benasher44 opened this issue Jun 21, 2024 · 3 comments
Closed

TS 5.5 type guards overly strict in some cases #58959

benasher44 opened this issue Jun 21, 2024 · 3 comments

Comments

@benasher44
Copy link

benasher44 commented Jun 21, 2024

πŸ”Ž Search Terms

  • predicate
  • guard
  • type guard

πŸ•— Version & Regression Information

  • This changed between versions 5.4.x and 5.5

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/MYGwhgzhAEDKAOBTYBLMICiAnLB7L0iAHgC6IB2AJjNngQN4C+AUMwGYCu5wJKu50FBATI0mHPgAUiCVgBc0WvgCU0es2jQsiEhywCZdQeQgkw3RLjZwkqdEqwBuZi3ZcefAWVOTV6zcD8poSy0AC80OSIAO6Ksr7OmijWkkIiduJ00rLKfhqaWjp65InQLAFBuCCIAHQguADm2XQ1ALaIUGANiMrOLEA

πŸ’» Code

class SpecialError extends Error {}

function isSpecialError(error: Error) {
  return error instanceof SpecialError;
}

function test() {
  const error = new Error();
  if (isSpecialError(error)) {
    return;
  }
  console.log(error.message);
}

πŸ™ Actual behavior

Error: "Property 'message' does not exist on type 'never'."

Even if error isn't SpecialError, it's still of type Error, which means it has a message property.

πŸ™‚ Expected behavior

This should compile. The error not being a SpecialError does not mean the error isn't still of type Error, which has a message property.

Additional information about the issue

In TS 5.4, this was allowed, but it's broken as of 5.5. My initial thought was that this had something to do with automatic type predicates, but adding an explicit type guard to the function doesn't help.

@benasher44
Copy link
Author

benasher44 commented Jun 21, 2024

Interestingly, someone on my team discovered that adding a random getter to SpecialError works as a workaround:

class SpecialError extends Error {
  get blah() {
    return "blah";
  }
}

With that in place, the error goes away πŸ€”

It has to be a property/method other than message though

@MartinJohns
Copy link
Contributor

MartinJohns commented Jun 21, 2024

Interestingly, someone on my team discovered that adding a random getter to SpecialError works as a workaround:

That's because the types are structurally the same without an additional property.

This really didn't change, it was the same behavior in earlier TypeScript versions. Just in earlier versions your isSpecialError function is not inferred to be a type guard, it's just a function returning a boolean, while in 5.5 it now is inferred as a type guard. When you add a type annotation you get the same behavior in 5.4: function isSpecialError(error: Error): error is SpecialError. Respectively you get the old behavior in 5.5 by adding a return type annotation of boolean.

This works as intended. See also: https://github.com/microsoft/TypeScript/wiki/FAQ#what-is-structural-typing

@benasher44
Copy link
Author

Ah! I see. The fact that it's a different class doesn't matter. Because the types are structurally the same, the types may as well be the same, in the eyes of TypeScript. Makes sense! Closing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants