Specialize a type for generic function

早过忘川 提交于 2021-01-27 21:48:47

问题


Given this definition:

declare function foo<T>(): { bar: T }

// <T>() => { bar: T }
type Foo = typeof foo;

How can one provide specialization to the generic function by its type?

What I want to achieve is to be able to do something like this:

// { bar: number }
type FooResult = ReturnType<Foo<number>>;

But TypeScript complaints that Foo itself is not generic - the function it types is.


回答1:


TypeScript doesn't really support the kind of higher-order typing you'd need to get this from ReturnType... it's a known design limitation. So all you have available is a variety of workarounds. Here are the ones I can think of off the top of my head:

  • Do it manually. This is essentially a non-answer, but could be the best way forward since it doesn't rely on any weird type system tricks:

    type FooResult<T> = { bar: T };
    type FooResultNumber = FooResult<number>; // {bar: number}
    
  • Pretend to actually call foo() and get its result. TypeScript doesn't support arbitrary type queries, so type FooResult = typeof foo<number>() unfortunately does not compile. The following code is about as close as you can get:

    const __dummy = (true as false) || foo<number>();
    type FooResultNumber = typeof __dummy; // {bar: number}
    

    This introduces a dummy variable in your runtime code. The (true as false) || expression construct uses a type assertion to lie to the compiler. The compiler thinks you are doing false || expression, the type of which will be the same as the type of expression. What you are really doing at runtime is true || expression which short-circuits, returning true without ever evaluating expression. This means that foo() never gets called at runtime despite being in the code.

  • Another way to pretend to call foo() is with a dummy class... you will never instantiate the class but it lets the compiler reason about types:

    class __FooRunner<T> {
      result = foo<T>();
    }
    type FooResult<T> = __FooRunner<T>["result"];
    type FooResultNumber = FooResult<number>; // {bar: number}
    

    Again, this puts some junk in your runtime code, which may or may not be acceptable depending on your use cases.

Okay, hope that helps; good luck!

Link to code



来源:https://stackoverflow.com/questions/57142802/specialize-a-type-for-generic-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!