TypeScript如何标注原地修改输入参数类型的函数类型
解决方案
方案1:使用TS内置的asserts类型谓词
TS 3.7版本引入的asserts类型谓词就是专门为这种原地修改入参类型的场景设计的,你可以直接修改process函数的返回值类型标注,告诉TS:只要这个函数正常执行完成没有抛出异常,传入的raw参数就一定是Processed类型。
修改后的代码如下:
interface Raw { created: string; } interface Processed { created: Date; } // 标注函数执行后入参raw会被收窄为Processed类型 export function process(raw: Raw): asserts raw is Processed { (raw as unknown as Processed).created = new Date(raw.created); } function printSeconds(r: Raw): void { process(r); // 此处TS会自动将r的类型收窄为Processed,不会报编译错误 console.log(r.created.getSeconds()); }
这种方案不需要额外的类型断言,也不会产生任何运行时开销,完全符合你原地修改的需求。
方案2:适配数组map场景的重载写法
如果你需要在map等数组方法中使用process函数,单独的asserts签名无法满足需求(map需要函数有返回值),你可以给process函数加一个重载签名,类型上假装返回处理后的对象,实际还是返回原对象,完全没有拷贝开销:
// 直接调用时的原地修改签名 export function process(raw: Raw): asserts raw is Processed; // 用于map调用的签名,实际返回原对象无拷贝 export function process(raw: Raw): Processed; export function process(raw: Raw): Processed | void { (raw as Processed).created = new Date(raw.created); // 直接返回原对象,无内存拷贝 return raw as Processed; } // 使用示例 const rawArr: Raw[] = [{created: '2024-01-01'}]; // 直接得到Processed[]类型,无需额外断言 const processedArr = rawArr.map(process);
注意事项
这种标注方式的正确性需要你自己保障:TS不会检查函数内部逻辑是否真的完成了类型转换,只会信任你写的类型签名。如果你函数内部逻辑没有完成转换,会出现运行时类型错误。
内容的提问来源于stack exchange,提问作者ocket8888
相关产品推荐
相关产品推荐

