Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript merge mapped type created from union type

Tags:

typescript

I'm trying to create a mapped type from a union type of keys. For the sake of having a minimal example, the types simply map to themselves. The following generic returns the expected result

type Foo<Bar extends string> = {[name in Bar]: name}
type test = Foo<'test1' | 'test2'> //test = {test1: 'test1', test2: 'test2'}

However, i want to remove the string contraint and just return undefined if Bar is not a string. I did this in the following way

type Foo<Bar> = Bar extends string ? {[name in Bar]: name} : undefined
type test = Foo<'test1' | 'test2'>
//expected result: test = {test1: 'test1', test2: 'test2'}
//actual result: test = {test1: 'test1'} | {test2: 'test2'}

test is now a union type instead of a simple mapped type.

Is this expected behavior in typescript or should i file a bug report? And is there any way to get the behavior i want?

P.S. In case it can be of assistance, i'm trying to fix this line.

like image 666
Thijs Steel Avatar asked Jan 20 '26 06:01

Thijs Steel


1 Answers

Yes this is expected behavior, it's often useful feature called distributive conditional types.

But sometimes, like in your example, it gets in the way. The workaround is to wrap Bar type parameter in [] when it's used in condition test:

type Foo1<Bar extends string> = {[name in Bar]: name}
type test1 = Foo1<'test1' | 'test2'> //test1 = {test1: 'test1', test2: 'test2'}

type Foo2<Bar> = [Bar] extends [string] ? {[name in Bar]: name} : undefined;
type test2 = Foo2<'test1' | 'test2'> //test2 = {test1: 'test1', test2: 'test2'}
type test3 = Foo2<1>; // undefined
like image 108
artem Avatar answered Jan 22 '26 19:01

artem



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!