- Notifications
You must be signed in to change notification settings - Fork 13k
Description
Bug Report
🔎 Search Terms
type inference, inference, aliased condition, aliased conditional expression
🕗 Version & Regression Information
It started happening when the aliased conditional expressions were introduced in the following pull-request:
This issue is still present as of v4.4.2.
I was unable to test this on prior versions because aliased conditional expressions didn't exist previously.
⏯ Playground Link
Playground link with relevant code.
💻 Code
function hasOwnProperty<X extends {}, Y extends PropertyKey> (obj: X, prop: Y): obj is X & Readonly<Record<Y, unknown>> { return obj.hasOwnProperty(prop) } const isObject = (val: unknown): val is object => val !== null && typeof val === 'object' const isString = (val: unknown): val is string => typeof val === 'string' declare const x: unknown const isAnObject = isObject(x) const hasValidName = isAnObject && hasOwnProperty(x, 'name') && isString(x.name) if (hasValidName) { const res0 = x // object & Readonly<Record<"name", unknown>> const res1 = x.name // string }
If it can help, I generated a .types
file as well.
See the .types file contents.
=== tests/cases/compiler/_baguette.ts === function hasOwnProperty<X extends {}, Y extends PropertyKey> >hasOwnProperty : <X extends {}, Y extends PropertyKey>(obj: X, prop: Y) => obj is X & Readonly<Record<Y, unknown>> (obj: X, prop: Y): obj is X & Readonly<Record<Y, unknown>> { >obj : X >prop : Y return obj.hasOwnProperty(prop) >obj.hasOwnProperty(prop) : boolean >obj.hasOwnProperty : (v: PropertyKey) => boolean >obj : X >hasOwnProperty : (v: PropertyKey) => boolean >prop : PropertyKey } const isObject = (val: unknown): val is object => val !== null && typeof val === 'object' >isObject : (val: unknown) => val is object >(val: unknown): val is object => val !== null && typeof val === 'object' : (val: unknown) => val is object >val : unknown >val !== null && typeof val === 'object' : boolean >val !== null : boolean >val : unknown >null : null >typeof val === 'object' : boolean >typeof val : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" >val : unknown >'object' : "object" const isString = (val: unknown): val is string => typeof val === 'string' >isString : (val: unknown) => val is string >(val: unknown): val is string => typeof val === 'string' : (val: unknown) => val is string >val : unknown >typeof val === 'string' : boolean >typeof val : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" >val : unknown >'string' : "string" declare const x: unknown >x : unknown const isAnObject = isObject(x) >isAnObject : boolean >isObject(x) : boolean >isObject : (val: unknown) => val is object >x : unknown const hasValidName = isAnObject && hasOwnProperty(x, 'name') && isString(x.name) >hasValidName : boolean >isAnObject && hasOwnProperty(x, 'name') && isString(x.name) : boolean >isAnObject && hasOwnProperty(x, 'name') : boolean >isAnObject : boolean >hasOwnProperty(x, 'name') : boolean >hasOwnProperty : <X extends {}, Y extends PropertyKey>(obj: X, prop: Y) => obj is X & Readonly<Record<Y, unknown>> >x : object >'name' : "name" >isString(x.name) : boolean >isString : (val: unknown) => val is string >x.name : unknown >x : object & Readonly<Record<"name", unknown>> >name : unknown if (hasValidName) { >hasValidName : boolean const res0 = x >res0 : object & Readonly<Record<"name", unknown>> >x : object & Readonly<Record<"name", unknown>> const res1 = x.name >res1 : string >x.name : string >x : object & Readonly<Record<"name", unknown>> >name : string }
🙁 Actual behavior
The type of the name
property of x
is inferred as unknown
(cf. res0).
However, when accessing the property with x.name
(cf. res1), its type is correctly inferred as string
.
🙂 Expected behavior
The name
property should be inferred as string
when checking the properties of x
.
For example, as a developer, when typing x.
, I'm expecting to see name: string
in the "auto-completion" list, instead of name: unknown
.