首页 > 解决方案 > 在生成器函数中使用 yield 时,Typescript 不会推断承诺类型

问题描述

我正在使用 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/**/*"]
}

标签: javascripttypescriptaxiosgeneratormobx-state-tree

解决方案


TypeScript 无法推断yield操作的类型,因为这是由调用代码控制的。在您的情况下,听起来这个生成器正在被处理来自 axios 的承诺的代码使用,并通过在调用g.next. 如果您处于无法使用async/的环境中,这是有道理的await;生成器可用于让异步逻辑更清晰地流动,其中生成器由助手驱动,该助手从生成器获取承诺,等待它解决,然后将履行值传递回生成器next -yield主要负责await什么时候这样做。(co是一个能够以这种方式使用生成器的库的示例。)所以代码使用生成器期望生成器产生 aPromise并返回承诺的履行值。在这种情况下,这将产生 aPromise<AxiosResponse<T>>并返回 a 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和生成器的人来说,这里有一个生成器生成字符串、返回布尔值并使用数字的示例(操场链接):

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)

推荐阅读