在生成器函数中使用 Yield 时,Typescript 不会推断 Promise 类型

Kev*_*ker 6 javascript generator typescript axios mobx-state-tree

我使用 Axios 来处理一些 API 获取,并且在生成器中执行该调用;async/await不是这个特定项目的选择。由于某种原因,即使axios我的类型正确,any当我使用yield关键字时,打字稿也会推断出类型。

function* foo() {
  // axios.get is returning Promise<AxiosResponse<T>>
  // but data is being inferred as "any"
  const { data } = yield axios.get<T>(url); 
  
  // do some stuff with data
}
Run Code Online (Sandbox Code Playgroud)

如果我专门输入 axios 响应,它工作正常,但我觉得我错过了一些东西,因为 TS 不会自动获取类型

function* foo() {
  const { data }: AxiosResponse<T> = yield axios.get<T>(url); 
  
  // do some stuff with data
}
Run Code Online (Sandbox Code Playgroud)

我还缺少其他步骤或配置吗?

这是我的 tsconfig

function* foo() {
  // axios.get is returning Promise<AxiosResponse<T>>
  // but data is being inferred as "any"
  const { data } = yield axios.get<T>(url); 
  
  // do some stuff with data
}
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 4

TypeScript 无法推断yield操作的类型,因为它是由调用代码控制的。在您的情况下,听起来这个生成器正在被处理 axios 承诺的代码使用,并通过在调用中提供 axios 结果来响应g.next。如果您处于无法使用async/ 的环境中,这是有道理的awaitnext生成器可用于允许异步逻辑更清晰地流动,其中生成器由助手驱动,该助手从生成器获取承诺,等待它解决,然后通过\xc2\xa0\将履行值传递回生成器xe2\x80\x94在执行此操作时yield很大程度上扮演了 的角色await。(这是支持以这种方式使用生成器的库的一个示例。)因此使用co生成器的代码期望生成器生成 a并返回承诺的履行值。在这种情况下,这将产生一个并返回一个PromisePromise<AxiosResponse<T>>AxiosResponse<T>

\n

为了处理这个问题,您需要使用类型来注释该函数Generator,该类型接受三个类型参数:

\n
    \n
  • T- 生成器通过生成的类型yield
  • \n
  • TReturn- 生成器完成后返回的类型。
  • \n
  • TNext- 生成器消耗的类型(从 接收yield)。
  • \n
\n

因此,将其应用到您的示例中,我们将添加一个泛型类型参数foo并用以下注释对其进行注释Generator

\n
function* foo<T>(): Generator<Promise<AxiosResponse<T>>, ReturnType, AxiosResponse<T>> {\n    const { data } = yield axios.get<T>(url); \n    \n    // ...do some stuff with data...\n\n    return /*...something of `ReturnType` (or use `void` as the type argument above)... */;\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

对于那些不太熟悉yield生成器的人来说,这里有一个示例,其中生成器生成字符串,返回布尔值,并使用数字(游乐场链接):

\n
function* example(): Generator<string, boolean, number> {\n    const a = yield "a";\n    console.log(`Received ${a} for a`);\n    const b = yield "b";\n    console.log(`Received ${b} for b`);\n    const c = yield "c";\n    console.log(`Received ${c} for c`);\n    const flag = (a + b) > c;\n    return flag;\n}\n\nconst g = example();\nlet result = g.next();\nconsole.log(result.value);  // "a"\nresult = g.next(1);         // Passes 1 to the generator\n// (Generator logs "Received 1 for a")\nconsole.log(result.value);  // "b"\nresult = g.next(2);         // Passes 2 to the generator\n// (Generator logs "Received 2 for b")\nconsole.log(result.value);  // "c"\nresult = g.next(3);         // Passes 3 to the generator\n// (Generator logs "Received 3 for c")\nconsole.log(result.value);  // false (1 + 2 > 3 is false)\n
Run Code Online (Sandbox Code Playgroud)\n