Closed
Description
Bug Report
When dealing with a fairly large type produced by a generic, differences in types can lead to what should be compile-time errors being ignored. Example (see last // @ts-expect-error
).
🔎 Search Terms
A hard thing to search for, but I tried "deep" and "false negative" and didn't see anything.
🕗 Version & Regression Information
- This changed between versions 4.4.4 and 4.5.5
- Still broken on current nightly
⏯ Playground Link
Playground link with relevant code
💻 Code
type DeepBrand<T> = T extends string | number | boolean | symbol | bigint | null | undefined | void
? {
t: 'primitive'
value: T
}
: T extends new (...args: any[]) => any
? {
t: 'constructor'
params: ConstructorParameters<T>
instance: DeepBrand<InstanceType<Extract<T, new (...args: any) => any>>>
}
: T extends (...args: infer P) => infer R // avoid functions with different params/return values matching
? {
t: 'function'
this: DeepBrand<ThisParameterType<T>>
params: DeepBrand<P>
return: DeepBrand<R>
}
: T extends any[]
? {
t: 'array'
items: {[K in keyof T]: DeepBrand<T[K]>}
}
: {
t: 'object'
properties: {[K in keyof T]: DeepBrand<T[K]>}
stringKeys: Extract<keyof T, string>
numberKeys: Extract<keyof T, number>
symbolKeys: Extract<keyof T, symbol>
}
// @ts-expect-error string vs void
const t1: DeepBrand<() => void> = {} as DeepBrand<() => string>
// @ts-expect-error string vs void
const t2: DeepBrand<() => () => void> = {} as DeepBrand<() => () => string>
// @ts-expect-error string vs void (should error, doesn't)
const t3: DeepBrand<() => () => () => void> = {} as DeepBrand<() => () => () => string>
🙁 Actual behavior
The compiler failed to noticed the difference between void
and string
, when it's sufficiently "deep" in the expanded object.
🙂 Expected behavior
The compiler should have an error on the last line of the snippet.