如何通过TypeScript类型约束rows包含fieldNames指定的键
如何约束TypeScript Table类型中rows元素必须包含fieldNames指定的键
我当前的Table类型定义如下:
type Table = { fieldNames: { id: string, children?: string }, rows: Array<( Record<string, any> & { label: string, ... } )> };
但这个类型无法约束rows的元素必须包含fieldNames.id和fieldNames.children值对应的键,即使缺少这些键TypeScript也不会报错。需要修改类型定义,实现rows元素必须包含fieldNames指定的键的类型约束,同时保留自定义键名的灵活性。
正确示例(无报错)
const table = { fieldNames: { id: "uuid", children: "objects" }, rows: [ { uuid: 1, objects: 2, label: "示例行" } ] };
自定义键名的正确示例
const table = { fieldNames: { id: "MY_CUSTOM_ID_KEY", children: "MY_CUSTOM_CHILDREN_KEY" }, rows: [ { MY_CUSTOM_ID_KEY: "SOMETHING VERY GOOD", MY_CUSTOM_CHILDREN_KEY: "SOMETHING, DO NOT CARE", label: "自定义键行" } ] };
错误示例(应报错)
const table = { fieldNames: { id: "uuid", children: "objects" }, rows: [ { id: 1, children: 2, label: "错误行" } ] };
解决方案:使用泛型动态约束键名
通过泛型捕获fieldNames的具体类型,再利用索引访问类型动态生成rows元素必须包含的键约束:
// 定义泛型Table类型 type Table<TFieldNames extends { id: string; children?: string }> = { fieldNames: TFieldNames; rows: Array< // 必须包含fieldNames.id指定的键 Record<TFieldNames["id"], any> & // 如果fieldNames.children存在,则必须包含对应的键 (TFieldNames["children"] extends string ? Record<TFieldNames["children"], any> : {}) & // 保留原类型中的label字段要求 { label: string } >; }; // 辅助函数用于自动推断泛型类型 function createTable<T extends { id: string; children?: string }>(table: Table<T>) { return table; }
使用方式
用createTable包裹对象字面量,TypeScript会自动推断fieldNames的键值,并约束rows元素必须包含对应键:
合法使用
// 带children的情况 const validTable = createTable({ fieldNames: { id: "uuid", children: "objects" }, rows: [ { uuid: 1, objects: [{}], label: "有效行1" }, { uuid: 2, objects: [], label: "有效行2" } ] }); // 不带children的情况 const validTableWithoutChildren = createTable({ fieldNames: { id: "uuid" }, rows: [ { uuid: 1, label: "有效行" } ] });
非法使用(TypeScript会报错)
const invalidTable = createTable({ fieldNames: { id: "uuid", children: "objects" }, rows: [ // 报错:缺少uuid和objects键 { id: 1, children: [], label: "错误行" } ] });
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

