TypeScript cannot always infer the correct type through a user-defined type guard using the 'is' operator.
#57,189 opened on 2024幎1æ26æ¥
Repository metrics
- Stars
- Â (48,455 stars)
- PR merge metrics
-  (å¹³åããŒãž 6d 17h) (30d ã§ 9 merged PRs)
説æ
ð 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