Skip to content

Mapped Types should distribute over union types #28339

Description

Search Terms

Mapped Type Union

Suggestion

This might be a bug or an intentional consequence of the original design, but mapped types do not distribute over union types. The example below demonstrates what happens:

typeFoo={x: false;foo?: string}typeBar={x: true;foo: string}typeFooOrBar=Foo|BartypeMappedFooOrBar=Pick<FooOrBar,keyofFooOrBar>// the type of MappedFooOrBar will be { x: boolean; foo: string | undefined }// note how foo is now required even with x = false// and also how you're now allowed to set foo = undefined even with x = true

Use Cases

Higher order components that receive components whose props are union types.

This usually is not a problem but it is a problem if you are going to use Pick (or Omit) on their props. This is already a problem with react-redux's connect for example.

Examples

typeFoo={x: false;foo?: string}typeBar={x: true;foo: string}typeFooOrBar=Foo|Bar// input is a union type so this should distributetypeMappedFooOrBar=Pick<FooOrBar,keyofFooOrBar>// should be equivalent to a MappedFooOrBar that distributes over its inputtypeMappedFooBar=Pick<Foo,keyofFooOrBar>|Pick<Bar,keyofFooOrBar>

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript / JavaScript code
    • It probably is breaking but is a "good break" as far as I can tell.
  • 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. new expression-level syntax)

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