如何基于执行上下文收窄回调函数的签名类型?
如何基于执行上下文收窄回调函数的签名类型?
嘿,我最近碰到个有点棘手的小场景:得根据回调函数执行的上下文环境,来收窄它的签名类型。先给你看看我抽象出来的API设计,这样你能快速get到问题背景:
// 我的库对外提供的回调函数接口 interface SerializeContext { inline: (target: any, immediate?: boolean) => string | undefined; defer: (callback: () => string) => void; } // 用户自定义的序列化逻辑入口 function serialize(obj: any, ctx: SerializeContext) { // 这里会写具体的序列化逻辑,比如根据不同上下文调用不同的回调 }
简单说,我想要的是:当回调函数在不同的上下文场景下执行时,TypeScript能自动推断出更精确的签名类型,而不是一直用宽泛的any或者默认类型。琢磨了一阵,我找到了两个比较实用的解决思路:
思路1:用泛型给上下文接口加类型约束
我们可以给SerializeContext引入泛型参数,让它能跟着传入的目标对象类型自动收窄回调的参数类型:
// 泛型版本的上下文接口,T默认是any,也可以指定具体类型 interface SerializeContext<T = any> { // target的类型被约束为泛型T,不再是宽泛的any inline: (target: T, immediate?: boolean) => string | undefined; // 如果defer的回调需要依赖目标对象类型,也可以同步约束 defer: (callback: (target: T) => string) => void; } // 序列化函数也改成泛型,自动推断obj的类型作为T function serialize<T>(obj: T, ctx: SerializeContext<T>) { // 调用inline时,target自动被推断为T类型 const inlineResult = ctx.inline(obj); // defer的回调里,target也会自动收窄为T类型 ctx.defer((target) => { // 这里可以安全地使用T类型的方法,不用再手动类型断言 return typeof target === 'string' ? target : JSON.stringify(target); }); }
这样一来,不管是inline还是defer里的回调,都能根据传入的obj类型自动获得精确的签名约束,不用再写一堆类型断言。
思路2:用函数重载收窄不同场景的签名
如果我们的回调函数在不同参数组合下有不同的返回值或参数类型(比如inline的immediate参数为true时,返回值一定是string),可以用函数重载来实现场景化的签名收窄:
interface SerializeContext { // 重载签名1:当immediate为true时,返回确定的string inline: (target: any, immediate: true) => string; // 重载签名2:当immediate为false或不传时,返回string | undefined inline: (target: any, immediate?: false) => string | undefined; // defer的回调如果有不同场景,也可以用同样的方式重载 defer: (callback: () => string) => void; } function serialize(obj: any, ctx: SerializeContext) { // 这里TypeScript会自动推断返回值是string,不用再处理undefined的情况 const definiteResult = ctx.inline(obj, true); // 这里返回值是string | undefined,需要做空值判断 const optionalResult = ctx.inline(obj); if (optionalResult) { // 逻辑处理 } }
这种方式适合回调函数在不同参数场景下有明确的签名差异的情况,能让TypeScript根据调用时的参数自动推断出最精确的签名类型。
备注:内容来源于stack exchange,提问作者Yuxuan Zhang
相关产品推荐
相关产品推荐

