TypeScript中能否获取接口对象属性的实例化特定值?
TypeScript 表格列类型的类型安全优化
问题描述
原始表格列类型定义如下:
interface Column<T> { key: keyof T; title: string; format?: (value: T[keyof T], record: T) => string | number; }
其中<T>为表格记录的数据类型,列展示值通过key属性索引,format函数用于自定义格式化,接收列值(类型为T[keyof T])和记录本身。
问题在于T[keyof T]是<T>所有属性类型的联合类型。例如定义Person类型:
interface Person { name: string; weight: number; birthday: Date; }
T[keyof T]等价于string | number | Date。实例化带format的列对象时,TypeScript无法确定value的具体类型,导致报错:
const column: Column<Person> = { key: 'birthday', title: "Birth Date", format: (value) => value.getFullYear() // 报错:无法确认value为Date类型,无getFullYear方法 };
已知添加第二个泛型参数可解决单个列的类型问题:
export interface Column<T, K extends keyof T> { key: K; title: string; format?: (value: T[K], record: T) => string | number; }
此时需手动指定键名:
const column: Column<Person, 'birthday'> = { key: 'birthday', title: "Birth Date", format: (value) => value.getFullYear() };
但该方案实用性差——表格列几乎都以数组形式使用,需要单一类型声明,而非为每个列指定不同泛型参数。
核心需求:无需类型断言,通过接口/辅助类型让format的value类型自动匹配key对应的具体属性类型,同时支持数组用单一类型声明。
解决方案
将Column定义为联合类型,通过映射类型遍历T的所有键,生成每个键对应的列类型:
type Column<T> = { [K in keyof T]: { key: K; title: string; format?: (value: T[K], record: T) => string | number; }; }[keyof T];
原理说明
- 映射类型
{ [K in keyof T]: ... }会为T的每个键K生成对应的列类型,其中format的value类型精确为T[K]; - 最后通过
[keyof T]将映射类型转换为联合类型,每个联合成员对应T的一个键的列类型。
使用示例
const columns: Column<Person>[] = [ { key: 'name', title: '姓名', format: (value) => value.toUpperCase() // value自动推断为string }, { key: 'weight', title: '体重', format: (value) => `${value}kg` // value自动推断为number }, { key: 'birthday', title: '生日', format: (value) => value.getFullYear().toString() // value自动推断为Date } ];
此时数组使用单一Column<Person>[]类型声明,每个列的format函数参数类型会被TypeScript自动推断,完全满足类型安全需求,无需手动指定泛型或类型断言。
内容的提问来源于stack exchange,提问作者Chris B.
相关产品推荐
相关产品推荐

