TypeScript中如何基于数据类型实现动态函数调用?
TypeScript 类型安全的函数映射表实现
针对你遇到的联合类型分发时无法自动收窄类型的问题,可以通过类型映射+泛型约束的方式实现类型安全的函数映射表,彻底摆脱重复的switch逻辑,同时保证TypeScript的类型检查。
步骤1:定义DataType与数据类型的映射
首先创建一个类型,明确每个DataType对应的具体数据结构:
enum DataType { A = 'A', B = 'B', } interface DataA { id: number; type: DataType.A; fieldA: string; } interface DataB { id: number; type: DataType.B; fieldB: string; } // 定义DataType到对应数据类型的映射 type DataMap = { [DataType.A]: DataA; [DataType.B]: DataB; };
步骤2:定义通用处理函数类型
接下来定义一个通用类型,约束每个处理函数必须接收对应DataType的数据:
// 通用处理函数类型:接收对应DataType的数据,返回void type DataHandler<T extends DataType> = (data: DataMap[T]) => void;
步骤3:创建类型安全的函数映射表
现在创建映射表时,通过Record类型约束键为DataType,值为对应类型的处理函数,确保映射关系完全匹配:
// 对应的保存函数(保持原定义) const saveDataA = (data: DataA) => { /* 实现逻辑 */ }; const saveDataB = (data: DataB) => { /* 实现逻辑 */ }; const saveFuncMap: Record<DataType, DataHandler<DataType>> = { [DataType.A]: saveDataA, [DataType.B]: saveDataB, };
步骤4:实现类型安全的统一入口函数
最后,用泛型函数实现统一入口,利用data.type作为泛型参数,让TypeScript自动推导并收窄类型:
const saveData = <T extends DataType>(data: DataMap[T]) => { return saveFuncMap[data.type](data as DataMap[T]); };
扩展性说明
- 新增
DataType.C和DataC时,只需:- 在
DataType枚举中添加C = 'C' - 定义
DataC接口 - 在
DataMap中添加[DataType.C]: DataC - 实现
saveDataC并添加到saveFuncMap
- 在
- 对于
updateData、deleteData等其他操作,只需复制这套模式:创建对应的updateFuncMap、deleteFuncMap,复用DataMap和DataHandler类型即可,无需重复编写switch逻辑。
类型检查验证
调用saveData时,TypeScript会自动校验参数类型:
// 正确:符合DataA类型 saveData({ id: 1, type: DataType.A, fieldA: 'test' }); // 错误:fieldA缺失,TypeScript会提示类型错误 saveData({ id: 1, type: DataType.A }); // 错误:type为A但传入了fieldB,TypeScript会提示类型错误 saveData({ id: 1, type: DataType.A, fieldB: 'test' });
内容的提问来源于stack exchange,提问作者SnakesCantWearBoots
相关产品推荐
相关产品推荐

