在生成器函数中使用 yield 时,Typescript 不会推断承诺类型
Typescript does not infer promise type when using yield in a generator function
我正在使用 Axios 来处理一些 API 抓取,并且我正在生成器中执行该调用; async/await
不是这个特定项目的选项。出于某种原因,即使 axios
使我的类型正确,当我使用 yield
关键字时,打字稿仍在推断 any
类型。
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/**/*"]
}
TypeScript 无法推断 yield
操作的类型,因为它由调用代码控制。在你的例子中,听起来这个生成器正在被处理来自 axios 的承诺的代码使用,并通过在对 g.next
的调用中提供 axios 结果来响应。如果您处于无法使用 async
/await
的环境中,这是有道理的;生成器可用于允许异步逻辑更清晰地流动,其中生成器由从生成器获取承诺的助手驱动,等待它稳定下来,然后通过 next
将实现值传递回生成器— yield
在很大程度上扮演了 await
的角色。 (co
是一个以这种方式使用生成器的库示例。)所以代码 using 生成器期望生成器产生一个 Promise
并且它给出支持承诺的履行价值。在这种情况下,这将产生一个 Promise<AxiosResponse<T>>
并返回一个 AxiosResponse<T>
.
要处理这个问题,您需要使用 Generator
类型注释函数,它接受三种类型参数:
T
- 生成器 通过 yield
生成的 的类型。
TReturn
- 生成器 returns 完成时的类型。
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
和他们可能喜欢的生成器的人来说,这里有一个示例,其中生成器生成字符串,returns 一个布尔值,并使用数字(playground link):
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)
我正在使用 Axios 来处理一些 API 抓取,并且我正在生成器中执行该调用; async/await
不是这个特定项目的选项。出于某种原因,即使 axios
使我的类型正确,当我使用 yield
关键字时,打字稿仍在推断 any
类型。
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/**/*"]
}
TypeScript 无法推断 yield
操作的类型,因为它由调用代码控制。在你的例子中,听起来这个生成器正在被处理来自 axios 的承诺的代码使用,并通过在对 g.next
的调用中提供 axios 结果来响应。如果您处于无法使用 async
/await
的环境中,这是有道理的;生成器可用于允许异步逻辑更清晰地流动,其中生成器由从生成器获取承诺的助手驱动,等待它稳定下来,然后通过 next
将实现值传递回生成器— yield
在很大程度上扮演了 await
的角色。 (co
是一个以这种方式使用生成器的库示例。)所以代码 using 生成器期望生成器产生一个 Promise
并且它给出支持承诺的履行价值。在这种情况下,这将产生一个 Promise<AxiosResponse<T>>
并返回一个 AxiosResponse<T>
.
要处理这个问题,您需要使用 Generator
类型注释函数,它接受三种类型参数:
T
- 生成器 通过yield
生成的 的类型。TReturn
- 生成器 returns 完成时的类型。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
和他们可能喜欢的生成器的人来说,这里有一个示例,其中生成器生成字符串,returns 一个布尔值,并使用数字(playground link):
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)