我读过typescript如何扩展inferred types,但仍然不确定发生了什么here

type Def = {
  'T': { status: 5, data: {r: 'm'}},
}

function route<S extends keyof Def>
   (route: S, handler: () => Promise<Def[S]>) { }

route('T', async function () {
   return { status: 5, data: {r: 'm'} };
});

这在typescript操场上工作得很好,但不应该引发错误,因为typescript将第二个参数的类型推断为route()
我问是因为我对this code有意见。传递到() => {status: number, data: {r: string}}的函数被推断为Router::get而不是() => {status: number}。奇怪的是,当我删除() => {status: 200}路由(shown here)时没有出现错误。

最佳答案

这个简单的例子并不像预期的那样工作,文字类型加宽在这里不发生——函数route()是通用的,并且首先推断“cc>”,因为您在不指定其泛型类型参数“cc>”的情况下调用它。

route('T', async function () {
   return { status: 5, data: {r: 'm'} };
});

因此,首先,编译器必须从传递的实际参数类型中推断出S
通过查看第一个参数,文字S,它确定S为文字类型'T'
因此,立即返回类型的第二个参数,S变得固定为定义为'T'的对象文字类型。然后,编译器不需要推断异步函数的返回类型,它只需检查它是否符合() => Promise<Def[S]>(即符合)。
为什么这不起作用?AA>我不知道,但是我怀疑在Def['T']中的索引签名阻止了类型推断对Def['T']的影响。如果你把相似的索引签名添加到这个简单的例子中,你会得到同样的错误:
type DefBase = { [p in string]: {}}

interface Def extends DefBase {
  'T': { status: 5, data: {r: 'm'}},
}

function route<S extends keyof Def>
   (route: S, handler: () => Promise<Def[S]>) { }

route('T', async function () {
   return { status: 5, data: {r: 'm'} };
});

Argument of type '() => Promise<{ status: number; data: { r: string; }; }>' is not assignable to parameter of type '() => Promise<{ status: 5; data: { r: "m"; }; }>'.
  Type 'Promise<{ status: number; data: { r: string; }; }>' is not assignable to type 'Promise<{ status: 5; data: { r: "m"; }; }>'.
    Type '{ status: number; data: { r: string; }; }' is not assignable to type '{ status: 5; data: { r: "m"; }; }'.
      Types of property 'status' are incompatible.
        Type 'number' is not assignable to type '5'.

现在,为什么添加索引签名会对类型推断产生这种影响-我不知道。

09-30 16:47
查看更多