Martin Ždila
Martin Ždila

Reputation: 3219

How to type-map intersection per type in Typescript?

I have many interfaces like Foo, Bar, Baz, ... and I need to have union of their mapped types where mapping is always the same (eg. with Pick).

interface Foo {
  a: 'FooA';
  b: 'FooB';
}

interface Bar {
  a: 'BarA';
  b: 'BarB';
}

interface Baz {
  a: 'BazA';
  b: 'BazB';
}

I can do it "manually":

type A = Pick<Foo, 'a'> | Pick<Bar, 'a'> | Pick<Baz, 'a'>;
type B = Pick<Foo, 'b'> | Pick<Bar, 'b'> | Pick<Baz, 'b'>;

But I would like not to repeat myself. Following code doesn't do it as it unions the properties of types and maps it afterwards:

type Union = Foo | Bar | Baz;

type A = Pick<Union, 'a'>; // creates { a: 'FooA' | 'BarA' | 'BazA' } but I need { a: 'FooA' } | { a: 'BarA' } | { a: 'BazA' }
type B = Pick<Union, 'b'>;

Is there a way to do it?

Upvotes: 1

Views: 452

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249536

You can use the distributing behavior of conditional types:

type PickDistributed<T, K extends keyof T> = T extends object ? Pick<T, K> : never;

type Union = Foo | Bar | Baz;

type A1 = PickDistributed<Union, 'a'>; // creates Pick<Foo, 'a'> | Pick<Bar, 'a'> | Pick<Baz, 'a'>
type B1 = PickDistributed<Union, 'b'>;

Upvotes: 2

Related Questions