有没有办法获取生成器函数的返回类型?

7

我想获取生成器函数的返回类型。
例如:

function* test(){
  yield 'a';
  yield 123;

  return true;
}

// what I'm trying to get
type A = GetGeneratorReturn<test>; // -> A has type boolean

我目前正在从事的工作。

type B = ReturnType<ReturnType<typeof test>['next']>['value'];
// B has type `true | "a" | 123`

(我认为如果我获取联合类型B的第一个项目,就可以获得返回类型)


3
任何联合的成分排序都是编译器的实现细节,X | Y 等同于 Y | X ,因此将 XYX | Y 中提取出来的任何解决方案可能都存在潜在风险。为什么需要这个呢?一个使用案例可能有助于某人提供替代方案。 - jcalz
1
有方法可以做到这一点,可能会有人发布一个方法,但我想赞同jcalz的警告。不要这样做(或者如果你这样做了,请不要在任何生产代码中使用它)。 - Titian Cernicova-Dragomir
1
哦,我明白了,我想要获取生成器函数的返回类型。 - Thu San
2个回答

7

有一个未解决的问题涉及到这个问题,但它相当古老,而且看起来自从其他问题得到解决后,没有人关注它。我在这里和那里看到了最近提到它的情况。目前最相关的问题似乎是这个。如果这对你很重要,你可能想去GitHub上给这些问题点个赞。

目前,在TypeScript中生成器类型只能让您访问yield类型和return类型的未区分联合。不幸的是,您不能依赖联合类型的排序。这是编译器的实现细节;由于X | Y等同于Y | X,编译器可以自由更改其中之一。有时候它确实会这样做:

function* test() {
  yield 'a';
  yield 123;
  return true;
} // function test(): IterableIterator<true | "a" | 123>

function* oops() {
  yield true;
  yield 123;
  return 'a'
} // function oops(): IterableIterator<true | "a" | 123>
oops()的返回类型与test()的返回类型完全相同。这意味着提取联合类型的第一个/最后一个元素的想法是行不通的。
如果您可以更改生成器定义并且不介意一些幻影类型存在,那么可能有一些解决方法可用:
type Returnable<T> = { __returnedType?: T } & T
const ret = <T>(t: T) => t as Returnable<T>;
type GeneratorReturn<T extends (...args: any) => IterableIterator<any>> =
  ReturnType<T> extends IterableIterator<infer I> ?
  NonNullable<Extract<I, Returnable<unknown>>['__returnedType']> : never

function* test() {
  yield 'a';
  yield 123;
  return ret(true); // only use ret() here
} 

function* oops() {
  yield true;
  yield 123;
  return ret('a'); // only use ret() here
} 

type TestRet = GeneratorReturn<typeof test>; // true
type OopsRet = GeneratorReturn<typeof oops>; // "a"

这个方法在某种程度上可以解决问题,但可能不是你想要追求的。唉,很抱歉我无法在这里找到更好的答案。祝你好运!


5

现在,您可以像这样做:

type GeneratorReturnType<T extends Generator> = T extends Generator<any, infer R, any> ? R: never;
type TestType =  GeneratorReturnType<ReturnType<typeof test>>; // bool

playground


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接