如何用TypeScript约束数组内所有对象拥有完全一致的字段
结论
2021年发布的TypeScript版本完全可以实现该需求,核心用到的泛型推断、数组元素类型约束特性在2021年的TS版本中已经全部稳定支持。
实现方案
由于需要自动推断数组元素的具体字段,我们采用符合要求的包装辅助函数实现:
/** * 构造符合要求的同结构对象数组 * @param arr 输入数组,要求所有元素结构与第一个元素完全一致 */ const createMyArray = <T extends Record<string, unknown>, U extends T[]>( arr: [T, ...U] ): T[] => arr
实现说明
- 泛型
T会自动捕获数组第一个元素的字段结构作为基准类型 - 后续所有元素的类型被约束为必须是
T的子类型,字段名、字段类型必须完全匹配 - 默认开启TypeScript多余属性检查,后续元素出现基准类型以外的字段时会直接抛出编译错误
- 包装函数运行时仅直接返回原数组,无额外性能开销
校验效果测试
直接传入数组场景
// 校验通过 const myArray1 = createMyArray([{ foo: 2 }, { foo: 1 }]) // 校验失败:第二个元素缺少foo字段,存在多余的bar字段 const myArray2 = createMyArray([{ foo: 2 }, { bar: 1 }]) // 校验通过 const myArray3 = createMyArray([{ bar: 2 }, { bar: 1 }]) // 校验通过 const myArray4 = createMyArray([{ anyFieldName: 2 }, { anyFieldName: 1 }]) // 校验通过 const myArray5 = createMyArray([{ bar: 2, foo: 1 }, { bar: 1, foo: 2 }]) // 校验失败:第二个元素缺少foo字段 const myArray6 = createMyArray([{ bar: 2, foo: 1 }, { bar: 1 }])
map返回数组场景
// 校验失败:map分支返回不同结构,元素类型为 {bar: number} | {foo: number, bar: number} 不统一 const myArray7 = createMyArray([1,2,3].map((number) => { if (number === 2) { return { foo: 1, bar: 2 } } return { bar: 2 } })) // 校验通过:map返回的所有元素结构完全一致 const myArray8 = createMyArray([1,2,3].map((number) => { return { foo: 1, bar: 2 } }))
额外约束满足情况
- 仅编译时检查:所有校验逻辑均在编译阶段完成,无强制运行时校验逻辑
- 采用包装函数实现,符合要求
- 自动支持多余属性检查,后续元素出现基准结构以外的字段时直接编译报错
内容的提问来源于stack exchange,提问作者johann1301s
相关产品推荐
相关产品推荐

