如何实现API相同但参数选项不同的TypeScript策略对象?
问题描述
我在使用TypeScript泛型时遇到了编译器校验问题,想通过JavaScript对象实现策略模式选择器——每个策略共享统一API,但execute方法的参数类型随策略不同而变化。
现有代码如下:
enum Strategy { One, Two, ... } export interface StrategiesApi<TOptions> { delete(): void; execute(options: TOptions): void; } export type Strategies<TOptions> = { [key in Strategy]: StrategiesApi<TOptions>; }; const strategies = { [Strategy.One]: { delete: strategyOneDelete, execute: strategyOneExecute, ... }, [Strategy.Two]: { delete: strategyTwoDelete, execute: strategyTwoExecute, ... }, };
编写策略选择函数时:
export const getStrategy = <TOptions>(strategy: Strategy): StrategyApi<TOptions> => { const strategy = strategies[strategy]; if (!strategy) { throw new Error('Strategy not found'); } return strategy; };
TypeScript报错,提示TOptions无法匹配对应策略execute方法的参数类型。用类型断言return strategy as StrategyApi<TOptions>能绕过错误,但会丢失类型校验能力。
需求是:实现带泛型参数的策略模式选择器,避免完全显式声明返回类型,也不想手动编写每个策略的完整接口定义。
解决方案
核心是利用TypeScript的自动类型推导和索引类型关联,让策略与对应参数类型自动绑定,无需手动维护统一泛型或冗长接口。
1. 定义各策略的参数类型
先明确每个策略对应的execute参数结构:
// 策略One的参数类型 type StrategyOneOptions = { id: string; // 自定义参数字段 }; // 策略Two的参数类型 type StrategyTwoOptions = { count: number; // 自定义参数字段 };
2. 实现具体策略并让TS自动推导类型
先写好每个策略的具体方法,再组合成策略对象,TypeScript会自动推导每个策略的完整类型:
// 策略One的具体实现 const strategyOneDelete = () => { // 业务逻辑代码 }; const strategyOneExecute = (options: StrategyOneOptions) => { // 业务逻辑代码 }; // 策略Two的具体实现 const strategyTwoDelete = () => { // 业务逻辑代码 }; const strategyTwoExecute = (options: StrategyTwoOptions) => { // 业务逻辑代码 }; // 组合策略对象,TS自动推导每个属性的类型 const strategies = { [Strategy.One]: { delete: strategyOneDelete, execute: strategyOneExecute, }, [Strategy.Two]: { delete: strategyTwoDelete, execute: strategyTwoExecute, }, };
3. 编写类型关联的策略选择函数
通过索引类型查询提取策略对象的类型,让函数返回类型与传入的Strategy枚举值强关联:
// 提取自动推导的策略映射类型 type StrategyMap = typeof strategies; // 定义选择函数,泛型约束为Strategy枚举,返回对应策略的类型 export const getStrategy = <S extends Strategy>(strategy: S): StrategyMap[S] => { const selectedStrategy = strategies[strategy]; if (!selectedStrategy) { throw new Error('Strategy not found'); } return selectedStrategy; };
4. 使用效果
调用getStrategy时,TypeScript会自动根据传入的枚举值,推导对应策略的execute参数类型,保留完整的类型校验:
// 自动识别execute参数为StrategyOneOptions const strategyOne = getStrategy(Strategy.One); strategyOne.execute({ id: "123" }); // 类型正确 strategyOne.execute({ count: 10 }); // 类型报错,符合预期 // 自动识别execute参数为StrategyTwoOptions const strategyTwo = getStrategy(Strategy.Two); strategyTwo.execute({ count: 10 }); // 类型正确 strategyTwo.execute({ id: "123" }); // 类型报错,符合预期
内容的提问来源于stack exchange,提问作者Dez
相关产品推荐
相关产品推荐

