繁体   English   中英

TypeScript 泛型 - 回调函数推断

[英]TypeScript generics - callback function inference

我试图理解为什么当泛型是回调的返回类型时,Typescript 能够推断带有回调参数的函数的返回类型,但当泛型是回调函数的类型时却不能这样做。

没有具体的推论

const f = <T extends () => any>(callback: T) => callback()

// inference r: any
const r = f(() => 1)

但推理适用于

const f = <T extends any>(callback: () => T) => callback()

// inference r: number
const r = f(() => 1)

我认为这是编译器在对泛型类型执行某些操作时所做的简化。 它没有将每个操作表示为可能越来越复杂的泛型类型,而是将泛型类型参数扩展到其约束并使用它。 当您使用已知具有的键索引到泛型类型对象时,您会看到这种情况:

function foo<T extends { a: any }>(obj: T) {
  const a1 = obj.a; // any, why not T['a']?
  const a2: T['a'] = obj.a; // this works though
}

有关更多信息,请参阅microsoft/TypeScript#33181 在上面,编译器看到obj.a并在访问它的a属性之前将objT扩大到{a: any} 所以a1any类型。 如果编译器推迟了扩展,它可以将此属性表示为查找类型T['a'] 事实上,如果您显式地注释要保存为T['a']的变量,编译器不会抱怨。

调用泛型类型的函数似乎也会发生同样的情况(尽管我还没有找到提到这一点的规范文档):

function bar<T extends () => any>(fn: T) {
  const r1 = fn(); // any, why not ReturnType<T> ?
  const r2: ReturnType<T> = fn(); // this works though
}

如您所见, r1any类型,因为编译器在调用之前将fnT扩展到其约束() => any 如果编译器推迟了扩展,它可以将返回类型表示为ReturnType<T> (请参阅ReturnType 文档)。 同样,如果您手动将值注释为ReturnType<T> ,编译器不会抱怨它。

这使我想到了我认为适合您的解决方案/解决方法:手动注释函数的返回类型:

const f = <T extends () => any>(callback: T): ReturnType<T> => callback()

编译时没有错误,现在当你在回调中调用f ,你会得到一个更好的返回类型:

const r = f(() => 1); // number

Playground 链接到代码

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM