Skip to content

Type instantiation for type level generic functionΒ #62524

Open

Description

πŸ” Search Terms

type instantiation
type level generic function
generic return type

Related: #40542, #61133 and maybe #52035?

Edit: Just found #55435 and #40179

βœ… Viability Checklist

⭐ Suggestion

#47607 added support for instantiation expressions, but those do not apply at the type level. I understand it'd be ambiguous in some cases (#47607 (comment)), but in some cases there really isn't a reasonable workaround.

πŸ“ƒ Motivating Example

I actually have a very similar case to the example provided in #40542

const provideBox = () => {
    const box = <T>(value: T) => ({value});
    return box;
};

type BoxMaker = ReturnType<typeof provideBox>
// type BoxMaker = <T>(value: T) => { value: T; }

type Box1<T> = ReturnType<BoxMaker<T>>;
// Type 'BoxMaker' is not generic.(2315)

const box = undefined as unknown as BoxMaker;

type Box2<T> = ReturnType<typeof box<T>>;
//type Box2<T> = { value: T; }
Compiler Options
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "target": "ES2017",
    "module": "ESNext",
    "moduleResolution": "node"
  }
}

Playground Link: Provided

πŸ’» Use Cases

  1. What do you want to use this for?

In our case we have a more complex provideBox that accept arguments. We also need to rely on type inference for the generic type of the box function and its return value;

  1. What shortcomings exist with current approaches?

I cannot extract and export a generic type for a return value of a generic function if I don't have direct reference to the function.

  1. What workarounds are you using in the meantime?

The only workaround I found is to use a dummy runtime value to apply the type, and use and instantiation expression on that dummy value (see Box2 above)

Activity

  1. RyanCavanaugh commented on Oct 2, 2025

    @RyanCavanaugh
    Member

    Duplicate #40179

  2. mhofman commented on Oct 2, 2025

    @mhofman
    Author

    I'm not sure what I described can always be a duplicate of #40179
    In particular, there may not be runtime arguments to be provided, yet the result can be a generic (requiring explicit generic type on the function call).

  3. I-Enderlord-I commented on Nov 23, 2025

    @I-Enderlord-I

    This feature would be immensely useful when constructing types from generic types. I have seen the comment about ambiguity in #47607, but I honestly don't see why that would be a problem. At the time of type checking it is known whether a type identifier is generic or not. And when it is, instantiating a generic function inside it should simply not work. Think of

    type Test<X> = <Y extends X>(x: Y) => Y;

    There is simply no way to pass a concrete type into Y before specifying X as the constraint is not known. So writing

    type A = Test<string>;

    should obviously set X to string and not Y, resolving as

    type A = <Y extends string>(x: Y) => Y;

    and then making it possible to do

    type B = A<'a' | 'b'>;

    to get

    type B = (x: 'a' | 'b') => 'a' | 'b';
  4. I-Enderlord-I commented on Nov 23, 2025

    @I-Enderlord-I

    Also issues like #40179 are definitely not duplicates of, but merely included in this, as there the discussion is solely on return types. Having type instantiation would also allow

    // in library
    class Config<T> {
      ...
      get<K extends keyof T & string>(key: K): T[K];
      set<K extends keyof T & string>(key: K, value: SomethingComplicated<T, K>): void;
    }
    
    //in application
    type IConfig {
      a: string;
    }
    const config = new Config<IConfig>();
    function setA(value: Parameters<Config<IConfig>['set']<'a'>>[1]) {
      config.set('a', value);
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions