Having an object for theme's colors:
themeColors = {
primary: ['#fff', '#000'],
secondary: ['#DDD', '#333'],
error: ['#CCC', '#444']
}
We can assign type like this:
themeColor: Record<string, [string; string]>
How to add restriction first and second of tupel should be unique? I mean
themeColors = {
primary: ['#fff', '#000'],
secondary: ['#fff', '#333'],
}
or
themeColors = {
primary: ['#fff', '#000'],
secondary: ['#DDD', '#000']
}
shouldn't pass type checking, becouse have duplication ('#fff' in first case, '#000' in second case)
I belive it sould be close to this approach
Is there a way to define type for array with unique items in typescript?
You'll need a helper function to the inference and validation:
const themeColors = colors({
primary: ['#fff', '#000'],
secondary: ['#DDD', '#333'],
error: ['#CCC', '#444']
} as const);
Here's what that function would look like:
function colors<C extends Record<string, readonly [string, string]>>(c: {
[K in keyof C]: C[K] extends readonly [infer A, infer B]
? readonly [A, B]
& (A extends Omit<C, K>[keyof Omit<C, K>][0] ? never : {})
& (B extends Omit<C, K>[keyof Omit<C, K>][1] ? never : {})
: C[K];
}) { return c }
We go through each of the entries and check if the first or second string already exist in the other entries. If it is, we intersect the type with never
, otherwise, an empty object type {}
(which basically does nothing).
You won't get a super helpful error, but hey, it's still an error. If you moved the checks to before readonly [A, B]
, then TypeScript won't be able to infer the original type of C
and everything will break. This is the only method I have found which retains inference while still validating the input correctly. See the linked playground below with some examples.