TypeScript中合并关联变量处理函数的类型错误解决方法
问题背景
我有一个包含primary和secondary字段的ComboChartSpec结构,编写工具函数处理该结构时,分开定义两个函数可正常运行,但合并为一个通用函数后遇到TypeScript类型错误。希望尽量不修改JS对象结构,仅通过调整类型解决问题。
原始可运行代码
function process1() { const yAxisType = 'primary'; const otherYAxisType = 'secondary'; return { [yAxisType]: foo, [otherYAxisType]: bar } } function process2() { const yAxisType = 'secondary'; const otherYAxisType = 'primary'; return { [yAxisType]: foo, [otherYAxisType]: bar } }
合并后报错代码
function process(yAxisType: 'primary' | 'secondary') { const otherYAxisType = yAxisType === 'primary' ? 'secondary' : 'primary'; return { [yAxisType]: foo, [otherYAxisType]: bar } }
错误信息
Type '{ [x: string]: { fields: never[]; } | { type: "quantitative"; }; scale: { type: "quantitative"; }; }' is not assignable to type 'ComboChartAxisEncoding<"editor">'.
Type '{ [x: string]: { fields: never[]; } | { type: "quantitative"; }; scale: { type: "quantitative"; }; }' is not assignable to type 'ComboChartSingleAxisEncoding<"editor">'.
Type '{ [x: string]: { fields: never[]; } | { type: "quantitative"; }; scale: { type: "quantitative"; }; }' is missing the following properties from type '{ primary: ComboChartSingleAxisSectionEncoding<"editor">; secondary: ComboChartSingleAxisSectionEncoding<"editor">; scale: QuantitativeScale; }': primary, secondaryts(2322)
index.ts(85, 3): The expected type comes from property 'y' which is declared here on type 'ComboChartEncodingMap<"editor">'
补充类型定义与测试函数
export type ComboChartAxisEncoding = ComboChartSingleAxisEncoding | ComboChartDualAxisEncoding; export type ComboChartSingleAxisEncoding = { primary: ComboChartSingleAxisSectionEncoding; secondary: ComboChartSingleAxisSectionEncoding; scale: 'quantitative'; }; export type ComboChartSingleAxisSectionEncoding = { fields: number[]; }; export type ComboChartDualAxisEncoding = { primary: ComboChartDualAxisSectionEncoding; secondary: ComboChartDualAxisSectionEncoding; }; export type ComboChartDualAxisSectionEncoding = { fields: number[]; scale: 'quantitative'; }; function process1(): ComboChartAxisEncoding { const yAxisType: 'primary' | 'secondary' = 'primary'; const otherYAxisType: 'primary' | 'secondary' = 'secondary'; return { // this works [yAxisType]: { fields: [] }, [otherYAxisType]: { fields: [] }, scale: 'quantitative', }; } function process2<T extends 'primary' | 'secondary'>(yAxisType: T): ComboChartAxisEncoding { // 注意:此处存在笔误,分支应返回'primary'而非'secondary' const otherYAxisType = (yAxisType === 'primary' ? 'secondary' : 'primary') as (T extends 'primary' ? 'secondary' : 'primary'); return { [yAxisType]: { fields: [] }, [otherYAxisType]: { fields: [] }, scale: 'quantitative', }; }
解决方案
TypeScript无法自动推断计算属性对应的是确定的primary/secondary字段,导致返回对象被识别为字符串索引类型,无法匹配目标类型。以下是两种不修改JS对象结构的解决方式:
方式一:添加类型断言
直接将返回值断言为目标类型,明确告诉TypeScript返回对象的结构:
function process(yAxisType: 'primary' | 'secondary'): ComboChartSingleAxisEncoding { const otherYAxisType = yAxisType === 'primary' ? 'secondary' : 'primary'; return { [yAxisType]: { fields: [] }, [otherYAxisType]: { fields: [] }, scale: 'quantitative', } as ComboChartSingleAxisEncoding; }
方式二:优化泛型类型推断
通过泛型和Exclude类型,让TypeScript跟踪yAxisType的具体类型,准确识别返回对象的结构:
function process<T extends 'primary' | 'secondary'>(yAxisType: T): ComboChartSingleAxisEncoding { const otherYAxisType = yAxisType === 'primary' ? 'secondary' : 'primary' as Exclude<'primary' | 'secondary', T>; return { [yAxisType]: { fields: [] }, [otherYAxisType]: { fields: [] }, scale: 'quantitative', } as ComboChartSingleAxisEncoding; }
内容的提问来源于stack exchange,提问作者lzl124631x

