我在 Typescript 中有一个 Vue 项目,我遇到了一个关于将元组对象映射到联合对象类型的问题。
关于一些上下文,我正在研究后端端点的预期响应类型。目前,此端点接收 2 个值:一个枚举和一个字符串。根据枚举,响应对象将发生变化。
这是当前的实现:
const validations = {
email: ['isValid', 'isAvaliable'],
password: ['isMinLengthValid', 'hasUppercase', 'hasLowercase', 'hasSpecialChars', 'hasNumbers'],
iban: ['isValid', 'isRegistered']
} as const
type ValidationsMap = {
[T in keyof typeof validations]: typeof validations[T][number]
}
function validate<T extends keyof ValidationsMap>(type: T, value: string): Record<ValidationsMap[T], boolean> {
// Do something
}
现在 Backend 端点将再接收一个参数,响应对象也将依赖于它。
这是我试过的方法,但它不起作用:
const validations = {
portal: {
email: ['isValid', 'isAvaliable'],
password: ['isMinLengthValid', 'hasUppercase', 'hasLowercase', 'hasSpecialChars', 'hasNumbers'],
},
payment: {
email: ['isValid'],
iban: ['isValid', 'isRegistered']
}
} as const
type ValidationsMap = {
[S in keyof typeof validations]: {
[T in keyof typeof validations[S]]: typeof validations[S][T][number] // Error: Type 'number' cannot be used to index type...
}
}
function validate<S extends keyof ValidationsMap, T extends keyof ValidationsMap[S]>(service: S, type: T, value: string): Record<ValidationsMap[S][T], boolean> {
// Do something
}
有谁知道为什么这不起作用?
我认为将 Tuple 映射到 Union 的深度可能存在限制,但事实并非如此。
这可以正常工作:
type PortalEmailValidation = typeof validations['portal']['email'][number]
最佳答案
这似乎是 TypeScript 中的一个错误,如 microsoft/TypeScript#27709 中所述.类型检查器显然没有正确跟踪深度 index access 的约束键为 generic 时的类型.这个问题已经开放了很长时间,没有任何进展的迹象,所以现在我们所能做的就是解决它。
当编译器不接受 T[K]
形式的索引访问时的一种方法就是用conditional type inference , 比如 T extends Record<K, infer V> ? V : never
(使用 Record<K, V>
utility type )。如果K
是 T
的(非可选)键, 然后 T
将被视为 Record<K, V>
对于一些 V
,我们推断。
所以不是 typeof validations[S][T][number]
,我们可以写成typeof validations[S][T] extends Record<number, infer V> ? V : never
.或者等价地:
type ValidationsMap = {
[S in keyof typeof validations]: {
[T in keyof typeof validations[S]]:
typeof validations[S][T] extends { [k: number]: infer V } ? V : never
}
}
另一种方法是显式添加缺失的约束。如果你有一个类型 A
你知道可以分配给另一种类型 B
但是编译器不知道这个,那么你可以替换A
与 Extract<A, B>
(使用 the Extract<T, U>
utility type )编译器将接受它。它知道Extract<A, B>
可分配给 B
.假设你对 A
是正确的可分配给 B
, 然后 Extract<A, B>
将评估为 A
.
所以如果ValidationsMap[S][T]
可分配给 string
但是编译器看不到,我们可以写成Extract<ValidationsMap[S][T], string>
相反:
function validate<S extends keyof ValidationsMap, T extends keyof ValidationsMap[S]>(
service: S, type: T, value: string
): Record<Extract<ValidationsMap[S][T], string>, boolean> { // okay
return null!
}
关于javascript - typescript :将元组映射到联合类型似乎在嵌套对象中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72460550/