typescript - 如何在 TypeScript 中定义一组通用对象,每个项目都有不同的模板参数
问题描述
我正在尝试为表单定义一个字段数组,其中每个项目可能具有不同的类型。我已经定义了这些类型:
interface FormData{
value1:number
value2:number|null
value3:string
value4:boolean
}
interface Field<T,K extends keyof T,TV=T[K]>{
key:K&string
value:TV
validation?:(value:TV)=>boolean
}
定义单个字段可以正常工作:
const field:Field<FormData,'value1'>={
key:'value1',
value:1,
validation(value:number):boolean{
return value<3
}
}
但是当为多个项目定义一个数组时,像这样:
const fields:Field<FormData,keyof FormData>[]=[
{
key:'value1',
value:1,
validation(value:number):boolean{
return value<3
}
},
{
key:'value3',
value:'xxx',
validation(value:string):boolean{
return value!=='xxx'
}
}
]
打字稿是:
- 允许
value
是任何类型,只要它是number|null|string|undefined
(例如字符串value1
) - 抱怨这些
validation()
功能,因为它们不接受number|null|string|undefined
作为参数
有没有办法帮助 TS 推断数组中每个项目的正确类型?理想情况下,我还想将数组定义为Field<FormData>[]
.
我正在使用 TypeScript 4.3。
解决方案
如果您继续在键中使您的类型Field<T, K>
通用K
,那么您确实会发现Field<T, ??>
为不同的键表示一个数组很烦人K
。有很多方法可以使用映射元组来做到这一点,但实际上,这需要您指定或让编译器推断特定的键类型数组。但是你并不关心使用了哪些键,只要它们都是一些实际的键。
这是存在量化泛型的规范用例,TypeScript 不直接支持。(在microsoft/TypeScript#14466上有一个请求,但现在这是一个缺失的功能。)TypeScript 的泛型,就像大多数语言的泛型一样,是普遍量化的,您可以将其视为类型的无限交集。另一方面,存在量化的泛型充当类型的无限联合。
但是等等,你的FormData
接口,像大多数对象类型一样,有一个有限的键列表。你不需要无限的联合;你可以只使用一个工会!Field<FormData, K>
意思是,为每个K
in建立一个原始类型的联合keyof FormData
。这是定义它的一种方法:
type Field<T> = { [K in Extract<keyof T, string>]-?: {
key: K
value: T[K],
validation?: (value: T[K]) => boolean
} }[Extract<keyof T, string>];
这会为 中的每个键构建一个具有您想要的字段类型的映射类型,然后立即索引到该映射类型以获取其属性的联合。K
keyof T
您可以看到它使您需要的类型:
type FieldFormData = Field<FormData>;
/* type FieldFormData = {
key: "value1";
value: number;
validation?: ((value: number) => boolean) | undefined;
} | {
key: "value2";
value: number | null;
validation?: ((value: number | null) => boolean) | undefined;
} | {
key: "value3";
value: string;
validation?: ((value: string) => boolean) | undefined;
} | {
...;
} */
现在类型中没有明确K
提及,您可以使用Array<Field<FormData>>
:
const fields: Field<FormData>[] = [
{
key: 'value1',
value: 1,
validation(value: number): boolean {
return value < 3
}
},
{
key: 'value3',
value: 'xxx',
validation(value: string): boolean {
return value !== 'xxx'
}
}
]
它还会捕获错误:
const badFields: Field<FormData>[] = [
{ key: "value2", value: "oops" }, // error!
{ key: "value4", value: true } // okay
]
推荐阅读
- r - 在 R 中聚类用户;监控集群结构的变化以检测“消失”或“移动”集群的用户
- python - 重新格式化一个 numpy 数组
- javascript - 如何检索对象数组的某些属性并将其放入新的对象数组中?
- c# - 如何模拟 IMessageReceiver?
- tensorflow - 出于贡献目的从源代码更快地构建 tensorflow
- javascript - 将手风琴移到打开的手风琴旁边
- docker - 禁用清理使用 --rm 运行的容器
- ios - SwiftUI - 如何在视图基础上设置画外音语言?
- cakephp - 如何在 CakePHP 3 中找到 SecurityComponent 配置选项?
- sql-server - 尝试连接到 Microsoft SQL Server 19 时出现“Unicode 错误”