Closed
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:
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)