数组中不同关联泛型类型的类型安全实现问题
解决方案:用泛型约束确保操作类型与参数的关联
要解决这个问题,核心是让TypeScript严格检查数组中每个操作的type和operation类型是否匹配,避免联合类型数组导致的类型放宽问题。可以通过泛型类/泛型构造函数来实现:
方法一:泛型类
将CompoundOperation定义为泛型类,泛型参数约束为合法的操作数组,确保每个元素的类型关联不丢失:
type OperationTypes = "move" | "rotate" | "rename"; type OperationsMap = { move: [number, number]; rotate: number; rename: string; }; type OperationRaw<K extends OperationTypes> = { type: K; operation: OperationsMap[K]; }; // 泛型类,T约束为只读的合法操作数组 export class CompoundOperation<T extends readonly OperationRaw<OperationTypes>[]> { _operations: T; constructor(operations: T) { this._operations = operations; } } // ✅ 合法示例:类型检查通过 new CompoundOperation([ { type: "move", operation: [10, 20] }, { type: "rotate", operation: 90 }, { type: "rename", operation: "new-file" } ]); // ❌ 非法示例:类型错误(operation类型与move不匹配),符合预期 new CompoundOperation([{ type: "move", operation: "Default" }]);
方法二:泛型构造函数(非泛型类)
如果不需要类本身保留数组的具体类型信息,也可以仅在构造函数中使用泛型约束:
export class CompoundOperation { _operations: readonly OperationRaw<OperationTypes>[]; // 构造函数泛型约束传入的数组每个元素都是合法的OperationRaw constructor<T extends readonly OperationRaw<OperationTypes>[]>(operations: T) { this._operations = operations; } }
原理说明
原来的OperationRaw<OperationTypes>[]是联合类型数组,在部分宽松检查模式下,TypeScript无法保证单个元素内部type与operation的严格匹配。通过泛型约束,我们强制要求传入的数组每个元素都必须是某个具体的OperationRaw<K>(比如OperationRaw<"move">或OperationRaw<"rotate">),从而确保每个操作的类型关联不丢失。
内容的提问来源于stack exchange,提问作者Jurek O.
相关产品推荐
相关产品推荐

