Skip to content

Mapped Types should distribute over union types #28339

Closed
@Jessidhia

Description

@Jessidhia

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:

type Foo = { x: false; foo?: string }
type Bar = { x: true; foo: string }

type FooOrBar = Foo | Bar

type MappedFooOrBar = Pick<FooOrBar, keyof FooOrBar>

// 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

type Foo = { x: false; foo?: string }
type Bar = { x: true; foo: string }

type FooOrBar = Foo | Bar

// input is a union type so this should distribute
type MappedFooOrBar = Pick<FooOrBar, keyof FooOrBar>
// should be equivalent to a MappedFooOrBar that distributes over its input
type MappedFooBar = Pick<Foo, keyof FooOrBar> | Pick<Bar, keyof FooOrBar>

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