Skip to content

Keyword to make a generic "whatever its requirements are."Β #44918

Closed as not planned

Description

@SephReed

Suggestion

πŸ” Search Terms

infer generics, generic any, make generic match its requirements, auto generic

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

The TS compiler knows exactly what type of generics it is willing to allow. That type is known by the compiler, but sometimes extremely tormentful to try to recreate.

It would save unimaginable amounts of user time to be able to say: "this generic is whatever typescript thinks it must be".

πŸ“ƒ Motivating Example

type Foo<T extends { foo: string}> = Array<T>
type Bar<T extends { bar: string}> = Map<string, T>

class Qux<T extends auto = auto>() {
   public foo(): Foo<T> { return []; }
   public bar(): Bar<T> { return new Map(); }
}

// based off the generics which T is passed to, auto should become:
// { foo: string;  bar: string }

πŸ’» Use Cases

  1. Pretty much every single time you try to pass a generic type from one template to another, and you get an extremely complex error.

  2. In general, there needs to be more "escape hatches" on generics, because they have a very bad habit of taking a project hostage if ever you try to do something complex with them.

  3. Absolutely every single time the (user) error occurs of: "X meets requirements, but T could be instantiated with a bad (user error) type"

  4. Seriously, just all the time. For everything that it possibly can be used for, because wrestling generics is so rarely a satisfying or efficient use of time.

Activity

  1. RyanCavanaugh commented on Jul 6, 2021

    @RyanCavanaugh
    Member

    I don't know how one would reason about this. What do you propose happen if Foo and Bar were declared thusly?

    type Foo<T extends { foo: string } | { qux: number }> = Array<T>;
    type Bar<T extends { bar: string } | boolean> = Map<string, T>
  2. SephReed commented on Jul 6, 2021

    @SephReed
    Author

    The type would be:

    auto = { foo; bar; } | { qux; bar; }
    

    To do it programmatically, you can just start plugging in the union of types which match Foo into Bar (or vice versa) and it'll tell you what its missing:

    This one can not be resolved by any logic
    Screen Shot 2021-07-06 at 5 04 03 PM

    This one can easily be resolved with logic
    Screen Shot 2021-07-06 at 5 04 18 PM

  3. RyanCavanaugh commented on Jul 6, 2021

    @RyanCavanaugh
    Member

    I don't think this is workable given that answer -- it's combinatorially explosive in a way that actually would occur in reality

  4. SephReed commented on Jul 7, 2021

    @SephReed
    Author

    If you think it's hard for a computer, imagine what it must be like for humans.

    I'm sure you'll understand this: working with a client that can't tell you what they want, but are very adamant about what they don't want as soon you show them it... it would be really, really nice to have the client know what they want.

    Without such a feature, there is an obvious ceiling on the complexity of projects; and I've run into pretty hard on my last three. A feature like this would clean up those projects a ton, as well as saving a bunch of time.

  5. tjjfvi commented on Jul 7, 2021

    @tjjfvi
    Contributor

    I don't know how one would reason about this. What do you propose happen if Foo and Bar were declared thusly?

    type Foo<T extends { foo: string } | { qux: number }> = Array<T>;
    type Bar<T extends { bar: string } | boolean> = Map<string, T>

    Ryan Cavanaugh (@RyanCavanaugh) Wouldn't it just be the intersection, ({ foo: string } | { qux: number }) & ({ bar: string } | boolean)?

  6. SephReed commented on Jul 9, 2021

    @SephReed
    Author

    T6 (@tjjfvi) Yeah, it'd be that with some cleaning up, so to simplify the polynomial:

    ({ foo } | { qux }) & ({ bar } | boolean)
    ({ foo } & { bar }) | ({ foo } & boolean) | ({ qux } & { bar }) | ({ qux } & boolean) 
    { foo; bar } | never | { qux; bar } | never
    { foo; bar } | { qux; bar }
    

    Easy peasy. And when it comes to really complex types, TS could far out-perform humans, which would make projects with complex generics much more fun.

    Overall, I don't think the shoe of "too complex" fits here. Doubly so because the expectation is that people should be able to do this in their heads instead? Or maybe the projects I'm working on are the "too complex" aspect. I've definitely noticed that TS has shined much brighter on my big-but-simple projects than it has with small-but-complex ones.

  7. typescript-bot commented on Jun 21, 2023

    @typescript-bot
    Contributor

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

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

    SuggestionAn idea for TypeScriptToo ComplexAn issue which adding support for may be too complex for the value it adds

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions