如何使泛型回调函数类型正常生效?
如何使泛型回调函数类型正常生效?
我完全懂你遇到的这个困扰——你本来期望调用f("")后,passedString的类型会被推断成具体的""字面量,这样编译器就能检测到和"dfafa"比较的错误,但现在编译器好像“丢了”这个具体类型,而且你还不想给回调里的参数手动加类型标注,对吧?
先把你的问题代码贴出来方便大家理解:
function fn<R>(cb: <S1 extends string>(string: S1) => R) { return <S2 extends string>(str: S2) => cb(str) } const f = fn((passedString) => { return { passedString } }) // 这里本该报错,但实际没有——说明`passedString`的类型没被识别为"" export const someValue = f("").passedString === "dfafa"
问题出在哪?
核心原因是泛型的作用域和推断时机不匹配:你给回调函数本身加了<S1 extends string>泛型,这个泛型是每次调用回调时才确定类型的;而fn返回的函数又有自己的<S2 extends string>泛型,这时候编译器没办法把S2的具体字面量类型“传递”给回调的S1,最终导致passedString的类型被拓宽成了宽泛的string,而不是你期望的具体字面量。
满足你需求的解决方案(不用手动给回调参数加类型)
你可以把泛型参数提升到fn函数本身,让整个函数链的类型推断连贯起来,代码如下:
function fn<S extends string, R>(cb: (string: S) => R) { return (str: S) => cb(str) } const f = fn((passedString) => { return { passedString } }) // 现在编译器会正确报错:类型 "" 和类型 "dfafa" 进行相等比较可能是无意的 export const someValue = f("").passedString === "dfafa"
这个方案的原理是:把泛型S放在fn的外层,TypeScript会延迟类型推断——直到你调用f("")的时候,才会把S确定为具体的""字面量,同时回调里的passedString会自动从S推断出类型,完全不需要你手动给参数加标注,完美符合你的需求。
补充说明
你提到之前知道可以把泛型放在回调上,但那样必须手动给参数加类型,这个方案就彻底避开了这个痛点。而且这个写法还能保持灵活性:比如你调用f("hello"),passedString会自动被推断为"hello"类型,依然能正确触发类型检查。
备注:内容来源于stack exchange,提问作者Abdulramon jemil
相关产品推荐
相关产品推荐

