TypeScript:是否可以获取泛型函数的返回类型?

jsd*_*sdw 15 generics typeof typescript

我从某个模块中导出了一个函数,如下所示:

export function MyFunc<A>() {
    return {
        foo: (in: A) => void
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,在其他一些模块中,我希望能够讨论MyFunc. 由于我没有导出类型,我将使用typeof给定值来获取我想要的类型MyFunc理想情况下,我会执行以下操作

import { MyFunc } from "mymodule";
type MyFuncReturned<A> = ReturnType<typeof MyFunc<A>>;

function foo(): MyFuncReturned<string> {
   // ...
}
Run Code Online (Sandbox Code Playgroud)

哼,这不行;typeof只能传递一个值并且不喜欢我尝试指定该值的泛型类型。

我能做的最好的事情就是说服 TypeScriptMyFunc从我创建的值中推断出特定类型,然后为它们提供单独的类型别名,例如:

const myFuncStringReturn = MyFunc<string>();
type MyFuncStringReturn = typeof myFuncStringReturn;
Run Code Online (Sandbox Code Playgroud)

为了避免实际运行MyFunc只是为了获取类型信息,我可以将它隐藏在一个函数后面并ReturnType在它上面使用:

const myFuncStringReturn = () => MyFunc<string>();
type MyFuncStringReturn = ReturnType<typeof myFuncStringReturn>;

const myFuncBoolReturn = () => MyFunc<bool>();
type MyFuncBoolReturn = ReturnType<typeof myFuncBoolReturn>;
Run Code Online (Sandbox Code Playgroud)

这给了我一种方式,一次一种,谈论 的不同返回类型MyFunc,但它

  • 涉及要编写的实际运行时代码,TS 可以从中推断出。
  • 不要让我MyFunc在更一般的意义上谈论。

我能想出的唯一“正确”解决方案是在声明时复制一堆类型信息MyFunc

export function MyFunc<A>(): MyFuncReturns<A> {
    return {
        foo: (in: A) => void
    }
}

export type MyFuncReturns<A> = {
    foo: (in: A) => void
}
Run Code Online (Sandbox Code Playgroud)

但是现在当我改变时MyFunc,我必须确保MyFuncReturns与它保持同步。

有什么方法可以让我得到一个类型,比如MyFuncReturns<A>只给我们导出的 value MyFunc,而不必添加运行时代码或添加上面的样板?

Tit*_*mir 17

有一项提议允许使用typeof任意表达式,以允许获取特定类型参数的泛型函数的返回类型(参见此处此处

今天有效的更通用的解决方法是使用具有与函数的返回类型相关联的字段的通用类。然后我们可以提取类的字段。因为对于类,我们可以在类型表达式中指定泛型类型参数,所以我们可以提取返回类型的泛型形式:

export function MyFunc<A>() {
  return {
    foo: (os : A) => {}
  }
}

class Helper <T> {
  Return = MyFunc<T>()
}
type FuncReturnType<T> = Helper<T>['Return']
type ForBool = FuncReturnType<boolean> //  {foo: (os: boolean) => void;}
type ForString = FuncReturnType<string> //  {foo: (os: string) => void;}
Run Code Online (Sandbox Code Playgroud)

注意如果您有限制,A则需要THelper和上复制这些限制,FuncReturnType不幸的是,这是不可避免的。


小智 5

等了很久,TypeScript 终于支持了。从 v4.7 开始(在撰写本文时仍处于测试阶段),借助实例化表达式功能,我们现在可以执行以下操作:

function myFunc<A>() {
  return {
    foo: (a: A) => { }
  }
}

type MyFuncReturnType<A> = ReturnType<typeof myFunc<A>>;

const a: MyFuncReturnType<string> = {
  foo: (a) => {
    console.log(a.toUpperCase());
  }
};

const b: MyFuncReturnType<number> = {
  foo: (a) => {
    console.log(a.toFixed(2));
  }
};
Run Code Online (Sandbox Code Playgroud)

我创建了这个游乐场,以便人们可以玩它。请参阅此处此处了解更多信息。