如何使用TypeScript条件类型验证对象数组的结构正确性?
问题与解决方案
问题描述
我们的应用通过条件类型基于对象的type属性处理对象数组的结构,用这些对象定义操作序列供引擎执行。但当前代码中,当对象的type为Payloads.B时,传入不符合要求的propA作为payload属性,TypeScript类型检查器并未抛出错误,无法自动验证payload的正确性。
原代码示例:
type payloadA = { propA: string; } type payloadB = { propB: boolean; } enum Payloads { A = 'A', B = 'B', } type conditionalPayload<T extends Payloads> = T extends Payloads.A ? payloadA : T extends Payloads.B ? payloadB : never; type myObj<T extends Payloads> = { type: T; payload: conditionalPayload<T> } // 使用数组的数组结构,与实际代码一致 const myArray: myObj<Payloads>[][] = [ [ { type: Payloads.A, payload: { propA: 'dummy', }, }, { type: Payloads.B, payload: { propA: 'dummy', // 期望此处报错,但当前未触发 }, }, ], ];
问题原因
当把myObj<Payloads>作为数组元素类型时,TypeScript会将其解析为单一对象类型:{ type: Payloads; payload: payloadA | payloadB },而非我们期望的myObj<Payloads.A> | myObj<Payloads.B>联合类型。这意味着类型检查器只会验证type属于Payloads、payload属于payloadA或payloadB,不会强制type与payload的结构一一对应。
解决方案
我们需要让操作类型成为严格的联合类型,确保每个操作的type和对应payload强绑定。有两种实现方式:
方式一:直接定义联合类型
显式列出所有操作类型的联合,让TypeScript严格检查每个元素必须匹配联合中的某一个完整结构:
type payloadA = { propA: string; } type payloadB = { propB: boolean; } enum Payloads { A = 'A', B = 'B', } // 定义所有合法操作的联合类型 type Operation = | { type: Payloads.A; payload: payloadA } | { type: Payloads.B; payload: payloadB }; // 数组类型改为 Operation[][] const myArray: Operation[][] = [ [ { type: Payloads.A, payload: { propA: 'dummy', }, }, { type: Payloads.B, payload: { propA: 'dummy', // 此处会立即触发类型错误,符合预期 }, }, ], ];
方式二:利用映射类型生成联合类型
如果操作类型较多,可通过映射类型自动生成联合类型,避免重复编写:
type payloadA = { propA: string; } type payloadB = { propB: boolean; } enum Payloads { A = 'A', B = 'B', } type conditionalPayload<T extends Payloads> = T extends Payloads.A ? payloadA : T extends Payloads.B ? payloadB : never; type myObj<T extends Payloads> = { type: T; payload: conditionalPayload<T> } // 通过映射类型生成所有 myObj<T> 的联合类型 type Operation = { [K in Payloads]: myObj<K> }[Payloads]; const myArray: Operation[][] = [ [ { type: Payloads.A, payload: { propA: 'dummy', }, }, { type: Payloads.B, payload: { propA: 'dummy', // 此处触发类型错误 }, }, ], ];
两种方式都能让TypeScript强制验证每个操作的type与payload结构严格匹配,当传入不符合的payload时立即抛出类型错误。
内容的提问来源于stack exchange,提问作者Jesus Diaz Rivero
相关产品推荐
相关产品推荐

