TypeScript如何优雅校验对象属性并在值为null时抛出异常?
优雅处理TypeScript对象null属性校验与类型转换方案
先优化重复类型定义
首先用TypeScript泛型工具类型自动生成MyType的非null版本,避免手动复制属性的冗余操作:
type MyType = { key1?: string | null key2?: string | null key3?: string | null // 更多属性... }; // 通用工具类型:移除对象所有属性的null类型 type NotNull<T> = { [K in keyof T]: Exclude<T[K], null> }; // 自动生成非null版本的类型,无需手动维护 type MyTypeNotNull = NotNull<MyType>; function logMyType(type: MyTypeNotNull) { console.log(type); }
方案一:用断言函数实现校验+类型断言
写一个通用的断言函数,遍历对象所有属性检查是否存在null,同时通过asserts语法告诉TypeScript:执行完这个函数后,对象的类型已经是NotNull<T>。
// 通用断言函数:检查对象是否含null属性,是则抛出异常 function assertNoNullProperties<T>(obj: T): asserts obj is NotNull<T> { for (const key in obj) { // 只检查自身可枚举属性,避免遍历原型链 if (Object.prototype.hasOwnProperty.call(obj, key) && obj[key] === null) { throw new Error(`属性 ${key} 不能为null`); } } } const myType: MyType = { key1: 'myKey1', // key2 省略 key3: null, // 更多属性... }; const run = (value: MyType) => { // 执行断言,存在null则抛出异常 assertNoNullProperties(value); // 此时TypeScript会自动识别value为MyTypeNotNull类型 logMyType(value); }; run(myType); // 执行时会抛出错误:属性 key3 不能为null
方案二:用类型守卫函数实现校验
如果更倾向于用条件判断而非断言语法,可以写一个类型守卫函数,返回布尔值的同时缩小对象类型:
// 通用类型守卫:检查对象是否不含null属性 function hasNoNullProperties<T>(obj: T): obj is NotNull<T> { for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key) && obj[key] === null) { return false; } } return true; } const run = (value: MyType) => { if (!hasNoNullProperties(value)) { throw new Error("对象包含null属性"); } // 条件分支内TypeScript会识别value为MyTypeNotNull类型 logMyType(value); };
方案优势
- 代码复用:断言/守卫函数是通用的,可直接用于其他类似结构的对象类型
- 维护成本低:新增
MyType属性时,无需修改校验逻辑和MyTypeNotNull类型,自动同步 - 避免冗余:代替大量重复的
if (xxx === null)判断,代码更简洁
内容的提问来源于stack exchange,提问作者Gerrol
相关产品推荐
相关产品推荐

