我正在尝试在 typescript 中处理模型验证。 我希望能够捕获验证定义的嵌套类型。
例如,我希望能够创建这样的验证器。
const validateUser = createValidator({
name: {
first: {
value: "First"
},
last: {
value: "Last"
}
},
age: {
value: 32
},
hasOnboarded: {
value: false
}
});
这将创建一个 validateUser 函数,该函数采用指定的模型 输入并验证其类型。
我希望能够捕获类型,以便 validateUser 知道接受, 符合接口(interface)的对象。
type ValidateUser = typeof validateUser;
应该是类型
(
model: {
name: {
first: string,
last: string
},
age: number,
hasOnboarded: boolean
}
) => boolean
这在 TypeScript 中可能吗?
最佳答案
确实如此,使用 2.8 的功能、条件类型和 infer
关键字。
declare function createValidator<
T extends {
[key: string]: { value: any } | { [key: string]: { value: any } }
}>(modelDescriptor: T): (validationSubject: {
[key in keyof T]: T[key] extends { value: infer R }
? R
: {
[innerKey in keyof T[key]]: T[key][innerKey] extends { value: infer R } ? R : never
}
}) => boolean;
// const validateUser: (validationSubject: { name: { first: string; last: string; }; age: number; hasOnboarded: boolean; }) => boolean
const validateUser = createValidator({
name: {
first: {
value: "First"
},
last: {
value: "Last"
}
},
age: {
value: 32
},
hasOnboarded: {
value: false
}
});
让我们分解一下,因为这有点复杂。
首先,我们的函数接受类型参数 T
,其约束条件是它必须是一个对象,其中每个键必须是 {value: any}
或一个嵌套对象,其中每个键都是这样的 {value: any}
.
我们的返回类型是一个对象,这样对于 T 中的每个键,我们都会检查类型。如果是 {value: <whatever>}
类型,推断<whatever>
(并称之为 R
),该键值的类型是 R (也称为 value
键下原始值的任何类型)。
如果不是 {value: <whatever>}
类型,那么根据我们最初的约束,它的类型必须是 {[key: string]: {value: <whatever>}}
,因此返回类型成为该内部对象的第二级映射,再次提取 value
中的任何内容的类型。嵌套对象的。
如果两者都不是(由于我们的限制,这是不可能的),则键的返回类型将为 never
。这部分永远不应该达到。
关于Typescript 嵌套类型映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53073110/