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

问题描述 投票:0回答:1

我使用 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
}

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

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

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

这是我的 tsconfig

{
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": false,
    "module": "commonjs",
    "target": "es6",
    "jsx": "react",
    "removeComments": true,
    "allowJs": true,
    "skipLibCheck": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "rootDirs": ["src", "src/stories"],
    "paths": {
      "*": ["./src/custom-types/*"]
    },
    "types": ["@emotion/core", "jest"]
  },
  "include": ["./src/**/*"]
}

javascript typescript axios generator mobx-state-tree
1个回答
5
投票

前言:你说过你不能使用

async
/
await
,因为你正在使用
mobx-state-tree
,这意味着你不能在受保护的树上使用它。但请参阅这篇文章了解如何成功使用
async
/
await
。 (基本上,您不是直接更新
async
函数中的内容,而是调用一个操作来执行此操作。)它位于 Tyler Williams 的博客上,他是
mobx-state-tree
的贡献者之一。我是2024年3月找到的;不知道它是什么时候写的,它没有注明日期 ☹️ 并且不在 archive.org 中。他说他们正在努力更新
mobx-state-tree
文档。

回答发电机问题:

TypeScript 无法推断

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

要处理这个问题,您需要使用

Generator
类型来注释该函数,该类型接受三个类型参数:

  • T
    - 生成器通过 yield 生成
    的类型。
  • TReturn
     - 生成器完成后
    返回的类型。
  • TNext
  • - 生成器
    消耗
    的类型(从yield接收)。
    
    
  • 因此,将其应用到您的示例中,我们将向
foo

添加一个泛型类型参数,并用

Generator
:
 对其进行注释
function* foo<T>(): Generator<Promise<AxiosResponse<T>>, ReturnType, AxiosResponse<T>> { const { data } = yield axios.get<T>(url); // ...do some stuff with data... return /*...something of `ReturnType` (or use `void` as the type argument above)... */; }

对于那些不太熟悉 
yield

和生成器的人来说,这里有一个示例,其中生成器生成字符串,返回布尔值,并使用数字(

playground 链接
): function* example(): Generator<string, boolean, number> { const a = yield "a"; console.log(`Received ${a} for a`); const b = yield "b"; console.log(`Received ${b} for b`); const c = yield "c"; console.log(`Received ${c} for c`); const flag = (a + b) > c; return flag; } const g = example(); let result = g.next(); console.log(result.value); // "a" result = g.next(1); // Passes 1 to the generator // (Generator logs "Received 1 for a") console.log(result.value); // "b" result = g.next(2); // Passes 2 to the generator // (Generator logs "Received 2 for b") console.log(result.value); // "c" result = g.next(3); // Passes 3 to the generator // (Generator logs "Received 3 for c") console.log(result.value); // false (1 + 2 > 3 is false)

© www.soinside.com 2019 - 2024. All rights reserved.