microsoft / microsoft/TypeScript
TypeScript cannot always infer the correct type through a user-defined type guard using the 'is' operator.
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 117
Description
🔎 Search Terms
"typeguard", "is operator"
🕗 Version & Regression Information
Tested with typescript@5.1.3 and later
⏯ Playground Link
No response
💻 Code
enum kind {
a = 'a',
b = 'b',
c = 'c'
}
type ID = {
id: number
}
class Test<T extends kind> {
value: T extends kind.a | kind.b ? ID : undefined
type: T
constructor(
type: T,
value: T extends kind.a | kind.b ? ID : undefined
) {
this.type = type
this.value = value
}
hasID(): this is Test<Exclude<kind, kind.c>> {
return this.type !== kind.c
}
do() {
if (this.hasID()) {
return this.value.id // Error: this.value: Object is possibly 'undefined'
// return (this as Test<Exclude<kind, kind.c>>).value.id // this works
}
}
}
🙁 Actual behavior
TypeScript cannot infer that 'this' is of type 'Test<Exclude<kind, kind.c>>' even though there is a type guard. In the 'do' method, TypeScript throws a TSError stating that 'this.value': Object is possibly 'undefined'.
If we explicitly cast 'this' as 'Test<Exclude<kind, kind.c>>', we can access the 'value' attribute, and it works as it should. However, somehow the type guard does not have the same effect.
🙂 Expected behavior
Since there is a type guard around the 'this.value.id' line, TypeScript should handle 'this' as a 'Test<Exclude<kind, kind.c>>' type. At least, that's what type guards are for in my understanding.
Additional information about the issue
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the supplied TypeScript reproduction and trace how the type checker narrows this after the hasID() user-defined type guard. Add a compiler regression test for the expected this.value.id access, then verify that the diagnostic is removed without weakening checks for the kind.c case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100