如何提升TypeScript中Lens辅助构造函数的泛型索引类型安全性?
TypeScript Lens 类型安全优化方案
1. forProperty 无需重复传参的类型安全实现
核心思路是让属性名与投影类型自动关联,通过将属性名作为约束为 keyof S 的泛型参数,让 TypeScript 自动推导投影类型为该属性对应的类型,彻底避免手动指定泛型时的不匹配和重复传参问题:
class GenericLens<S, P> { constructor( public readonly get: (source: S) => P, public readonly set: (source: S, value: P) => S ) {} // 优化后的 forProperty static forProperty<S, K extends keyof S>(prop: K): GenericLens<S, S[K]> { return new GenericLens( (source) => source[prop], (source, value) => ({ ...source, [prop]: value }) ); } }
用法说明
- 无需手动指定投影类型
P,TypeScript 会根据传入的属性名自动推导:interface User { name: string; age: number; } // 自动推导投影类型为 string const nameLens = GenericLens.forProperty<User>('name'); // 传入非法属性名会直接触发类型错误 const invalidLens = GenericLens.forProperty<User>('invalidProp'); // 类型报错 - 彻底解决了属性名与投影类型不匹配的问题,也不需要重复传递属性名相关的泛型参数。
2. forProperties 类型安全优化(匹配长度、顺序、类型)
利用 TypeScript 的元组类型映射特性,将属性名数组的每个元素约束为 S 的键,并自动推导每个位置对应的属性类型,确保属性名数组与投影元组的长度、顺序、类型完全一一对应:
class GenericLens<S, P> { constructor( public readonly get: (source: S) => P, public readonly set: (source: S, value: P) => S ) {} // 优化后的 forProperties static forProperties<S, K extends readonly (keyof S)[]>( ...props: K ): GenericLens<S, { [I in keyof K]: S[K[I]] }> { return new GenericLens( (source) => props.map(prop => source[prop]) as { [I in keyof K]: S[K[I]] }, (source, values) => { const updated = { ...source }; props.forEach((prop, idx) => { updated[prop] = values[idx]; }); return updated; } ); } }
用法说明
- 属性名数组的长度、顺序、每个元素的合法性都会被 TypeScript 严格校验:
interface User { name: string; age: number; email: string; } // 自动推导投影类型为 [string, number] const nameAgeLens = GenericLens.forProperties<User>('name', 'age'); const user = { name: 'Alice', age: 30, email: 'alice@example.com' }; const [name, age] = nameAgeLens.get(user); // name 为 string,age 为 number // 传入非法属性名触发类型错误 const invalidPropsLens = GenericLens.forProperties<User>('name', 'invalidProp'); // 类型报错 // 修改属性顺序后,投影元组的类型会自动同步 const ageNameLens = GenericLens.forProperties<User>('age', 'name'); // 投影类型为 [number, string] - 完全解决了属性名数组与泛型元组不匹配的问题,无需手动指定元组类型,所有类型推导由 TypeScript 自动完成。
内容的提问来源于stack exchange,提问作者MBauerDC
相关产品推荐
相关产品推荐

