如何编写包装函数修复TypeScript中reason可选转必填的类型错误?
问题描述
我有一个updateJob函数,其参数类型为ChangeRequest<string>,相关接口和函数定义如下:
export interface ChangeRequest<T> { readonly value: T; readonly reason: string; } export async function updateJob( id: UUID, p1?: ChangeRequest<string>, p2?: ChangeRequest<string> )
当前调用该函数时出现TypeScript类型错误,原因是我的changes对象中reason属性被推断为可选类型(即便示例中写了具体值,实际场景里可能存在reason为undefined的情况):
let changes = { "p1" : {"value":"asdf", "reason":"abc"}, "p2" : {"value":"earth", "reason":"abc123"}, }
调用代码:
updateJob(id, changes.p1, changes.p2);
错误信息:
argument of type
{readonly value: string;} | undefined is not assignable to parameter of type 'ChangeRequest<string> | undefined
请问能否编写一个包装函数,将可选的reason属性转为必填属性,以解决该类型错误?
解决方案
当然可以,下面提供几种类型安全的实现方式:
方法一:带校验的包装转换函数
这个函数会检查输入对象是否包含有效reason属性,符合要求则返回标准ChangeRequest<T>类型对象,否则抛出错误(可根据业务需求调整错误处理逻辑):
function toChangeRequest<T>(input: { value: T; reason?: string } | undefined): ChangeRequest<T> | undefined { if (!input) return undefined; // 校验reason必须是非空字符串 if (typeof input.reason !== 'string' || input.reason.trim() === '') { throw new Error('ChangeRequest必须包含非空的reason属性'); } // 返回只读的标准ChangeRequest对象 return Object.freeze({ value: input.value, reason: input.reason }) as ChangeRequest<T>; }
调用方式:
updateJob(id, toChangeRequest(changes.p1), toChangeRequest(changes.p2) );
方法二:类型守卫函数
如果不想抛出错误,而是在类型层面确保传入值的合法性,可以用类型守卫:
function isChangeRequest<T>(input: unknown): input is ChangeRequest<T> { return typeof input === 'object' && input !== null && 'value' in input && 'reason' in input && typeof (input as any).reason === 'string'; }
调用时结合守卫判断:
updateJob(id, isChangeRequest(changes.p1) ? changes.p1 : undefined, isChangeRequest(changes.p2) ? changes.p2 : undefined );
额外优化:直接修正changes的类型定义
如果changes的结构是确定的,也可以直接给它指定类型,避免TypeScript的自动推断偏差:
let changes: { p1?: ChangeRequest<string>; p2?: ChangeRequest<string>; } = { "p1" : {"value":"asdf", "reason":"abc"}, "p2" : {"value":"earth", "reason":"abc123"}, };
这样直接调用updateJob就不会出现类型错误了。
内容的提问来源于stack exchange,提问作者Blankman
相关产品推荐
相关产品推荐

