TypeScript枚举映射类型兼容问题:Shape类型转换报错求解
解决TypeShape映射器类型不兼容问题
问题原因
你定义的mapper用Record<ShapeType, (shape: Shape) => void>做类型约束,导致每个绘制函数的参数被宽泛地限定为Shape联合类型,但实际drawPolygon只接受Polygon、drawRectangle只接受Rectangle。TypeScript无法保证传入的Shape就是对应子类型,因此抛出类型不兼容错误。同时原调用逻辑mapper[shape.type](shape)虽然逻辑自洽,但需要更精确的类型定义让TS识别匹配关系。
解决方案(TS 4.9+ 推荐)
利用可辨识联合特性,结合satisfies关键字约束映射器结构,同时保留精确的类型推断:
enum ShapeType { POLYGON = 'polygon', RECTANGLE = 'rectangle' } interface Polygon { type: ShapeType.POLYGON; points: Array<[number, number]>; } interface Rectangle { type: ShapeType.RECTANGLE; points: [[number, number], [number, number]]; } type Shape = Polygon | Rectangle; // 关联ShapeType与对应具体Shape类型 type ShapeMap = { [ShapeType.POLYGON]: Polygon; [ShapeType.RECTANGLE]: Rectangle; }; // 定义映射器类型:每个键对应接受对应Shape子类型的函数 type ShapeHandlerMap = { [K in keyof ShapeMap]: (shape: ShapeMap[K]) => void; }; const drawPolygon = (toDraw: Polygon): void => {}; const drawRectangle = (toDraw: Rectangle): void => {}; // 使用satisfies确保结构合规,同时保留精确类型推断 const mapper = { [ShapeType.POLYGON]: drawPolygon, [ShapeType.RECTANGLE]: drawRectangle } satisfies ShapeHandlerMap; const toDraw: Array<Shape> = []; // TS自动识别shape.type与函数参数的匹配关系,无报错 toDraw.forEach((shape) => mapper[shape.type](shape));
低版本TS兼容方案
如果你的TS版本低于4.9(不支持satisfies),可以通过泛型函数辅助类型推断:
// 手动指定映射器类型 const mapper: ShapeHandlerMap = { [ShapeType.POLYGON]: (shape: Polygon) => drawPolygon(shape), [ShapeType.RECTANGLE]: (shape: Rectangle) => drawRectangle(shape) }; // 泛型函数提取对应类型的Shape function handleShape<K extends ShapeType>(shape: Extract<Shape, { type: K }>) { mapper[shape.type](shape); } const toDraw: Array<Shape> = []; toDraw.forEach(handleShape);
原理说明
ShapeMap和ShapeHandlerMap将映射器的函数参数类型精确限定为对应子类型,避免了宽泛联合类型的不兼容问题。- 可辨识联合特性让TypeScript通过
shape.type自动缩小shape的类型范围,确保调用时参数类型与函数要求完全匹配。
内容的提问来源于stack exchange,提问作者Léal
相关产品推荐
相关产品推荐

