GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Can't infer return type of generic function · Issue #55435 · microsoft/TypeScript

Can't infer return type of generic function #55435

New issue
Copy link
New issue
Copy link
Closed as not planned
Closed as not planned
Can't infer return type of generic function#55435
Copy link
Labels
DuplicateAn existing issue was already createdAn existing issue was already created

Description

@AFatNiBBa
Sean Alunni (AFatNiBBa)
opened on Aug 19, 2023
Issue body actions

🔎 Search Terms

infer generic function return type

🕗 Version & Regression Information

  • Before version 3.5.1 the syntax wasn't supported
  • Before and during version 4.8.4 there was an additional bug for which the type of a (In the example) was [ true, true ]
  • 5.2.0-beta doesn't fix the issue

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.1.6#code/FAehAIHUHsCcGsDO5C8G4WR3gG9jl+ALgJ4AOApuAMIAWpAxvADwAqANOAArikAe+pAdgBNkACm4AucAEN+hAJTgAvAD5wAI2jQANqRmrFHLrwHDwYyUwUqCsAK7kA-DfvhJAMylbEpANzAceGBQcEjgAO4AlvhU4LTQALbEOtxGxLCkiIgR0PyIAbhEZOAAkogActD4AIzM+pQ09MxsDACqyubgLVaqLUZ8QshV4E4eXuSS+Hakyn54BCTkUkrgANol5ZU1AEzKbKUV1QxVqgC6s4EQuAB6Dv5zQTAIyOn4trD8EfwA5gQ04J-EWz4fLzIqlJhTWrLah0RiscC1DqWJSqJgzEGFchqZZrcGQyb2XbrCH2Bijbync64ILXW4AX38QQAItAMvwAOT4cIhMwAIVsP2IUlg+DkWBBzNZiA5XPg-GgYX++GQAKBGIWlE8WgYADE+iZkDrbPxaPhsvw2ABBWBfZA8fqmdJSQQ5LSEcDGuUK-grE51PX2g1mAB0oeFtsk1tt3X+-DcpFgnWGSck-FIADcE1TQeRaNCtQxERJwMjrPC1kM-RLLuAbncLuADlxM-xwDlpG20wBaIWwKTxUh8RNZRJaCJuCKkQTgTOwLI5dVFChamoB4wDcBGk1mnJsNHLNcO0TF0uqT7xxO9Jy9VMZrOL8jTgzLrRaGpFiwx+HHat4Ou-lk2U5bkEHCKIYjiUceFSdJMnNPI5kxLh81fd80SRGM1nhLZwBONgf3uGt-0I4InnCGhW2iBNFnSGVwC+AQEwiWgELwJDShqfdnwLDoqhjAlSDYLDcPRRCNTcHF1hqASiQ4o5KV-WlgDpIA

💻 Code

// Works 👍
{
    type Check<T, P extends (x: any) => boolean> = P extends (x: T) => true ? true : false;

    // Works with complex expressions
    type IsNot1<T> = Check<T, <U>(x: U) => U extends 1 ? false : true>;
    type a = [ IsNot1<2>, IsNot1<1> ];
    //   ^? type a = [ true, false ]

    // Works returning the input
    type IsTrue<T> = Check<T, <T>(x: T) => T>;
    type b = [ IsTrue<true>, IsTrue<false> ];
    //   ^? type b = [ true, false ]
}

// Doesn't work (Bug part)
{
    // Doesn't know its input
    type Call<F extends Function, Args extends readonly unknown[]> = F extends (...args: Args) => infer U ? U : never;
    type c = Call<<T>(x: T) => T, [ 1 ]>
    //   ^? type c = unknown

    // Not even on a one-parameter simplified version
    type Call1<F extends Function, T> = F extends (x: T) => infer U ? U : never;
    type d = Call1<<T>(x: T) => T, 1>
    //   ^? type d = unknown

    // Doesn't work with complex expressions
    type e = Call1<<T>(x: T) => [ T, 2 ], 1>
    //   ^? type e = [ unknown, 2 ]

    // Works when there aren't generics
    type Is1<T> = Call<(x: 1) => true, [ T ]>;
    type f = [ Is1<true>, Is1<1> ];
    //   ^? type f = [ never, true ]
}

🙁 Actual behavior

Types c, d and e[0] are unknown

🙂 Expected behavior

Types c, d and e[0] should have all been 1.
I tried to infer the return type of some generics functions when they got supplied with certain types, I can check wether the return type is something else (true inside Check in this example) but I cannot actually get it

Additional information about the issue

No response

Activity

  1. jcalz commented on Aug 19, 2023

    @jcalz
    Joe Calzaretta (jcalz)
    on Aug 19, 2023
    Contributor
    More actions

    TS doesn't have true call types of the sort you'd need for this to work.

    Looks like a duplicate of #52035 (or at least this comment) and refers back to #6606.

  2. AFatNiBBa commented on Aug 20, 2023

    @AFatNiBBa
    Sean Alunni (AFatNiBBa)
    on Aug 20, 2023
    Author
    More actions

    I think this is something that has to be looked into because it has great potential and it almost works.
    Consider the following:

    type FilterObject<T, P extends (v: any, k: any, t: any) => boolean> = { [k in keyof T as P extends (v: T[k], k: k, t: T) => true ? k : never]: T[k] };
    
    type Test = { ab: 1, ac: 2, cb: 3, ad: 1, g: "g" };
    
    type a = FilterObject<Test, (v: 1) => true>;
    //   ^? type a = { ab: 1, ad: 1 }
    
    type b = FilterObject<Test, <K>(_: any, k: K) => K extends `a${string}` ? false : true>;
    //   ^? type b = { cb: 3, g: "g" }
    
    type c = FilterObject<Test, <V, K>(v: V, k: K) => K extends V ? true : false>;
    //   ^? type c = { g: "g" }

    It understands what the return type is, so why can't it infer it

  3. fatcerberus commented on Aug 20, 2023

    @fatcerberus
    Bruce Pascoe (fatcerberus)
    on Aug 20, 2023
    More actions

    It seems like you want specifically #40179

    Reacted by Joe Calzaretta, Sean Alunni and Martin Johns
  4. jcalz commented on Aug 20, 2023

    @jcalz
    Joe Calzaretta (jcalz)
    on Aug 20, 2023
    Contributor
    More actions

    Yeah #40179 was the one I was searching for but "call types" wasn't mentioned there

  5. Ryan Cavanaugh (RyanCavanaugh)
    added
    DuplicateAn existing issue was already createdAn existing issue was already created
    on Aug 21, 2023
  6. steveluscher commented on Aug 22, 2023

    @steveluscher
    Steven Luscher (steveluscher)
    on Aug 22, 2023
    More actions

    I'm also blocked from making one of my more complicated types generic because of this. The satisfies keyword is able to expand all of the possible return types of doThing below, so can we make infer do the same?

    type WrapConfig = { wrap?: boolean };
    
    type ReturnValue<TWrapConfig extends WrapConfig | void, T> =
      TWrapConfig extends object
      ? TWrapConfig['wrap'] extends true ? T[]
      : T
      : T;
    
    function doThing<TWrapConfig extends WrapConfig | void = void>(
      config?: TWrapConfig
    ): ReturnValue<TWrapConfig, string> {
      return (config?.wrap ? ['hi'] : 'hi') as ReturnValue<TWrapConfig, string>;
    }
    
    // Test that the function return type is parametric on the shape of the arguments
    doThing({ wrap: true }) satisfies string[];
    doThing({ wrap: false }) satisfies string;
    doThing({}) satisfies string;
    doThing() satisfies string;
    
    // Test that the function, without type parameter, spans the union of return types
    doThing satisfies ((...args: any[]) => string[] | string);
    
    // Try to infer the return type without supplying the type parameter
    type DoThingReturn = typeof doThing extends (...args: any[]) => infer R ? R : unknown;
    (null as unknown as DoThingReturn) satisfies string[] | string; // ERROR
    Output
    "use strict";
    function doThing(config) {
        return ((config === null || config === void 0 ? void 0 : config.wrap) ? ['hi'] : 'hi');
    }
    // Test that the function return type is parametric on the shape of the arguments
    doThing({ wrap: true });
    doThing({ wrap: false });
    doThing({});
    doThing();
    // Test that the function, without type parameter, spans the union of return types
    doThing;
    null; // ERROR
    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",
        "jsx": "react",
        "module": "ESNext",
        "moduleResolution": "node"
      }
    }

    Playground Link: Provided

  7. Steven Luscher (steveluscher)
    added a commit that references this issue on Aug 22, 2023

    refactor(experimental): reduce `getProgramAccounts` types using generics

    a6e1058
  8. typescript-bot commented on Aug 25, 2023

    @typescript-bot
    TypeScript Bot (typescript-bot)
    on Aug 25, 2023
    Contributor
    More actions

    This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  9. TypeScript Bot (typescript-bot)
    closed this as not plannedon Aug 25, 2023
  10. microsoft
    locked as resolved and limited conversation to collaborators on Oct 22, 2025
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

    DuplicateAn existing issue was already createdAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.