Skip to content

Infer generic types from property valueΒ #46329

Closed

Description

Suggestion

πŸ” Search Terms

Infer generics from property enum

βœ… 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

Consider the following example

interface OptsMap {
    numString: {
        num: Number;
        boolOrString: String;
    },
    boolBool: {
        bool: Boolean;
        boolOrString: Boolean;
    },
}

interface OptsContainer<T extends keyof OptsMap> {
    type: T;
    opts: OptsMap[T];
}

type OptsList = OptsContainer<keyof OptsMap>[];

I would then like to be able to have intellisense show only the possible values based on the first type specified:
image
Rather than showing bool, boolOrString and num, it should only show bool and boolOrString.
Furthermore, boolOrString should be of type bool rather than bool | string.

Also, when parsing an array like this, it should infer the type of entries by their type value. I.e. the following should not error:

const x : OptsList = [];

for (const entry of x) {
    if (entry.type == "boolBool") {
        console.log(entry.opts.bool);
//                             ^^^^
// Property 'bool' does not exist on type '{ num: number; boolOrString: string; }'
    }
}

πŸ“ƒ Motivating Example

πŸ’» Use Cases

I have an api that quickly generates a list of user interfaces which looks a little something like this:

createGuiList([
    {
        type: "num",
        guiOpts: {
            min: 10,
            max: 50,
        },
    }, {
        type: "string",
        guiOpts: {
            maxLength: 100,
            multiLine: true,
        },
    }
]);

It would be nice to not have to provide a type for guiOpts every time it's used. I'm using jsdoc and currently that looks like this:

createGuiList([
    {
        type: "num",
        /** @type {import("../../../GuiManager.js").GuiOpts} */
        guiOpts: {
            min: 10,
            max: 50,
        },
    }, {
        type: "string",
        /** @type {import("../../../GuiManager.js").GuiOpts} */
        guiOpts: {
            maxLength: 100,
            multiLine: true,
        },
    }
]);

Activity

  1. andrewbranch commented on Nov 2, 2021

    @andrewbranch
    Member

    The type OptsList does not correlate its type and opts properties to a single constituent when instantiated with a union (that’s not possible). You’ve instantiated OptsContainer with a union type (keyof OptsMap), and so type is allowed to be either "numString" or "boolBool", and opts can be either {num: Number; boolOrString: String} or {bool: Boolean; boolOrString: Boolean;}. They don’t have to match up. This is the type system working exactly as it’s supposed to.

  2. jespertheend commented on Nov 2, 2021

    @jespertheend
    ContributorAuthor

    Huh, not sure how this happened but I somehow managed to unknowingly duplicate my own issue (#46552). Sorry about that.
    Either way, thanks for the extra explanation! This helps a lot :)

  3. locked as resolved and limited conversation to collaborators on Oct 21, 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

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions