如何设置泛型默认类型并允许覆盖?Table组件类型匹配问题
TypeScript Table组件
customLabel参数类型匹配问题解决 问题背景
开发从条目数组提取数据的Table组件时,通过dataKey指定提取字段,filter.key默认继承dataKey,也可手动覆盖。需要让customLabel函数的value参数类型严格对应Item[filter.key || dataKey],但以下场景类型推导失效:
- 同时传入
dataKey与filter.key时,value变为Item所有键的类型联合,而非Item[filter.key] - 仅传入
filter.key时,同样出现value类型为所有键联合的问题
其余两个场景(仅传dataKey、两者均不传)类型推导正常。
解决方案
通过泛型条件分发或工具类型推导,让TypeScript精准识别不同参数组合下的生效键,从而约束customLabel的value类型。
方案一:联合类型拆分场景
直接将组件Props拆分为四个场景的联合类型,每个场景单独约束类型:
type TableProps<Item> = // 场景1:仅传dataKey,filter.key继承dataKey { dataKey: keyof Item; filter?: { key?: never; customLabel?: (value: Item[keyof Item]) => string } } | // 场景2:同时传dataKey和filter.key,使用filter.key { dataKey: keyof Item; filter: { key: keyof Item; customLabel?: (value: Item[typeof filter.key]) => string } } | // 场景3:仅传filter.key,使用filter.key { dataKey?: never; filter: { key: keyof Item; customLabel?: (value: Item[typeof filter.key]) => string } } | // 场景4:两者都不传,强制报错 { dataKey?: never; filter?: never }; function Table<Item>(props: TableProps<Item>) { // 组件业务逻辑 return null; }
方案二:工具类型推导生效键
通过自定义工具类型提取实际生效的键,再约束customLabel的参数类型:
// 提取实际生效的键 type EffectiveKey<Props> = Props extends { filter: { key: infer K } } ? K : Props extends { dataKey: infer K } ? K : never; // 组件Props类型,强制必须传入dataKey或filter.key type TableProps<Item> = { dataKey?: keyof Item; filter?: { key?: keyof Item; customLabel?: (value: Item[EffectiveKey<TableProps<Item>>]) => string; }; } & ( | { dataKey: keyof Item } | { filter: { key: keyof Item } } ); function Table<Item>(props: TableProps<Item>) { // 组件业务逻辑 return null; }
场景验证
以User类型为例:
interface User { id: number; name: string; }
- 场景1:仅传dataKey
<Table<User> dataKey="id" filter={{ customLabel: (value) => value.toString() }} /> // value类型为number,推导正确
- 场景2:同时传dataKey和filter.key
<Table<User> dataKey="id" filter={{ key: "name", customLabel: (value) => value.toUpperCase() }} /> // value类型为string,推导正确,不再是number | string
- 场景3:仅传filter.key
<Table<User> filter={{ key: "name", customLabel: (value) => value.toUpperCase() }} /> // value类型为string,推导正确
- 场景4:两者均不传
<Table<User> /> // TypeScript报错,符合预期,强制开发者必须定义其中一个键
内容的提问来源于stack exchange,提问作者quez
相关产品推荐
相关产品推荐

