如何约束参数为超类型且保留返回值的完整类型信息?
类型安全的代码复用解决方案
问题背景
项目中有一批类型本应继承同一接口,但由于属性名与数据库绑定无法修改,无法实现继承。需要编写一个通用函数处理这些不同类型,通过传入适配信息实现逻辑复用,同时保留原类型的完整信息(包括非尺寸/位置相关的额外属性),避免返回值丢失类型信息。
当前代码的问题是:函数返回的对象只包含适配键对应的属性,丢失了原类型的其他属性(比如Chair的color),导致类型赋值错误。
修改后的实现代码
interface Sized { width: number; height: number; } interface Positioned { x: number; y: number; } /** * 调整元素位置使其适配容器 * @param element 目标元素,可包含任意额外属性 * @param container 容器对象 * @param elKeys 元素属性与标准尺寸/位置属性的映射 * @param cKeys 容器属性与标准尺寸属性的映射 * @param elementMinWidth 元素最小宽度 * @param elementMinHeight 元素最小高度 * @returns 调整后的原类型对象,保留所有原始属性 */ function fitElementIntoContainer< Element extends Record<string, any>, ElKeys extends Record<keyof (Sized & Positioned), keyof Element>, Container extends Record<string, any>, CKeys extends Record<keyof Sized, keyof Container> >( element: Element, container: Container, elKeys: ElKeys, cKeys: CKeys, elementMinWidth?: number, elementMinHeight?: number ) { // 复制原对象,保留所有属性 const mutEl = { ...element }; // 位置校正逻辑 if (mutEl[elKeys.x] < 0) mutEl[elKeys.x] = 0; if (mutEl[elKeys.y] < 0) mutEl[elKeys.y] = 0; // 边界适配逻辑 if (mutEl[elKeys.x] + mutEl[elKeys.width] > container[cKeys.width]) { mutEl[elKeys.x] = container[cKeys.width] - mutEl[elKeys.width]; } if (mutEl[elKeys.y] + mutEl[elKeys.height] > container[cKeys.height]) { mutEl[elKeys.y] = container[cKeys.height] - mutEl[elKeys.height]; } // 最小尺寸限制逻辑 if (elementMinWidth !== undefined && mutEl[elKeys.width] < elementMinWidth) { mutEl[elKeys.width] = elementMinWidth; } if (elementMinHeight !== undefined && mutEl[elKeys.height] < elementMinHeight) { mutEl[elKeys.height] = elementMinHeight; } return mutEl; } interface Chair { chairX: number; chairY: number; chairWidth: number; chairHeight: number; color: string; // 非尺寸相关的额外属性 } const exampleElement: Chair = { chairX: -3, chairY: 55, chairWidth: 40, chairHeight: 40, color: 'black' }; const exampleContainer = { cW: 555, cH: 3300 }; const containerKeys = { width: "cW", height: "cH" } as const; const chairKeys = { x: "chairX", y: "chairY", width: "chairWidth", height: "chairHeight" } as const; // 现在可以正确赋值为Chair类型,不会丢失color属性 const fitsIntoContainer: Chair = fitElementIntoContainer( exampleElement, exampleContainer, chairKeys, containerKeys );
关键修改点
- 泛型参数调整:将元素类型
Element作为顶层泛型,而非仅提取属性键,确保函数能识别并保留原类型的所有属性。 - 适配键类型约束:
ElKeys约束为Record<keyof (Sized & Positioned), keyof Element>,确保映射的键确实存在于原元素类型中,保证类型安全。 - 返回值类型自动推导:由于直接返回复制的原对象,TypeScript会自动推导返回值为
Element类型,完全保留原类型的所有属性。
内容的提问来源于stack exchange,提问作者NoBullsh1t
相关产品推荐
相关产品推荐

