0

Edited:

Having union types like these:

type SomeElements = 'element1' | 'element2'; type OtherElements = 'element3' | 'element4' | 'element1'; type MoreElements = 'element5' | 'element6'; const someElements: { [key in SomeElements]: key; } = { element1: 'element1', element2: 'element2', }; const otherElements: { [key in OtherElements]: key; } = { element3: 'element3', element4: 'element4', element1: 'element1' }; const moreElements: { [key in MoreElements]: key; } = { element5: "element5", element6: "element6", }; 

Is it possible to use type checking to know at compile time that allElements contains duplicate entries to avoid having to filter the array at runtime?

type Elements = SomeElements | OtherElements | MoreElements; const allElements: Elements[] = ( Object.values(someElements) as Elements[] ).concat( Object.values(otherElements) ).concat( Object.values(moreElements) ); /* allElements = ["element1", "element2", "element3", "element4", "element1", "element5", "element6"] */ const removeDuplicates = (strings: Elements[]) => strings.filter( (value, index) => strings.indexOf(value) === index ); const allElementsFiltered = removeDuplicates( ( Object.values(someElements) as Elements[] ).concat( Object.values(otherElements) ).concat( Object.values(moreElements) ) ); /* allElementsFiltered = ["element1", "element2", "element3", "element4", "element5", "element6"] */ 
2
  • 1
    I am not sure why you want to disallow it or get an error. Union elements are unique anyways so adding an existing element to a union won't modify it. Commented Aug 2, 2022 at 20:19
  • Does this answer your question? Type for "every possible string value except ..." Commented Aug 2, 2022 at 20:26

2 Answers 2

2

Yes, it's possible using Exclude. Example:

type SomeElements = 'element1' | 'element2'; type OtherElements = 'element3' | 'element4' | 'element1'; // Disallow this type Elements = Exclude<SomeElements, OtherElements>; let x: Elements; x = "element2"; 
Sign up to request clarification or add additional context in comments.

Comments

1

If you want to have compile-time error when two unions are overlapping, you could use a type-checking function similar to ts-expect.

First we define a generic type which returns true if two unions are not overlapping and false if otherwise.

type Union1 = 'element1' | 'element2'; type Union2 = 'element3' | 'element4'; type Union3 = 'element3' | 'element4' | 'element1'; type UniqueUnions<U1, U2> = (U1 extends U2 ? false : never) extends never ? true : false type T0 = UniqueUnions<Union1, Union2> // ^? type T0 = true type T1 = UniqueUnions<Union1, Union3> // ^? type T1 = false 

Now we need a function which expects true as the generic type.

const expect = <T extends true>() => {} expect<UniqueUnions<Union1, Union2>>() expect<UniqueUnions<Union1, Union3>>() // compile-time error 

If we pass two overlapping unions, we get a compile-time error.

Playground

1 Comment

Yes, this allowed me to accomplish what I wanted: Playground

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.