TypeScript cannot always infer the correct type through a user-defined type guard using the 'is' operator.
#57,189 建立於 2024年1月26日
倉庫指標
- Star
- (48,455 star)
- PR 合併指標
- (平均合併 6天 17小時) (30 天內合併 9 個 PR)
描述
🔎 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