请查看以下TypeScript代码段。 为什么不抛出编译错误?显然不是类型错误吗?我必须更改什么才能使其再次成为类型安全的? TYVM
type A<P> = {
p?: never,
q?: Partial<P>
}
type B<P> = {
p?: Partial<P>
q?: never
}
type C<P> = A<P> | B<P>
const c: C<{ a: number}> = {
p: {
a: 1,
b: 2 // <------ Why is this allowed?!?
}
}
console.log(c)
点击here进行演示
答案 0 :(得分:1)
这是known bug,其中excess property checking不适用于人们期望的涉及联合和交集的嵌套类型。多余的属性检查是类型系统的一个附加组件,它仅适用于对象文字,因此当它不适用时,情况会退回到structural subtyping规则中,其中类型{a: A, b: B}
是子类型{a: A}
的值,因此前一种类型的值应可分配给后一种类型的变量。如果您认为此案例比已经列出的案例更具吸引力,那么您可能想要转到the issue in Github并给出一个案例或解释您的用例。希望有一天会解决此问题。
不过,直到那时,我不确定该怎么做。等同于多余属性检查的类型级别称为exact types,它在TypeScript中不作为具体类型存在。有多种方法可以使用通用辅助函数进行模拟并进行类型推断...在您的情况下,它看起来像这样:
type Exactify<T, K extends keyof any>
= T & { [P in Exclude<K, keyof T>]?: never };
type A<P, K extends keyof any=never> = {
p?: never,
q?: Partial<Exactify<P, K>>
}
type B<P, K extends keyof any=never> = {
p?: Partial<Exactify<P, K>>
q?: never
}
type C<P, K extends keyof any = never> = A<P, K> | B<P, K>
type KeyofKeyof<T> =
keyof T | { [K in keyof T]: T[K] extends object ? keyof T[K] : never }[keyof T];
const asC = <T extends C<{ a: number }, KeyofKeyof<T>>>(c: T) => c;
const c = asC({
p: {
a: 1,
b: 2 // <------ error
}
})
是的,这很丑。不确定是否值得您这样做。它的工作方式是说C<P, K>
与您的C<P>
相同,只是增加了P
类型以明确排除K
中的所有其他属性。然后,根据给定的传入参数,使用辅助函数asC()
来推断K
的类型。由于有问题的键是向下嵌套一级的,因此我需要一种KeyofKeyof<T>
类型的键才能从一级向下提取键(不能在不触及循环类型的情况下对所有级别都进行此操作)。
现在出现所需的错误。好极了?我想。
无论如何,希望能有所帮助。祝你好运!