Is there an easy way to only allow one occurrence of a value in an array?
Lets say I have defined types like this:
array: {
value: boolean;
label: string;
}[];
I want to ensure that in that array, only one value can be true. If one value is true, the other values must be false. So for example I want to allow this:
const arr : array = [
{ value: false, label: '1' },
{ value: true, label: '2' },
{ value: false, label: '3' },
];
But I want typescript to fail and say that only one value can be true if I have an array like this:
const arr2 : array = [
{ value: true, label: '1' },
{ value: true, label: '2' },
{ value: false, label: '3' },
];
Is this possible in typescript?
Edit: To be sure, I only want to ensure this by types, not other logic
It is possible, however not really useful in the real world to do this at the type level (at least in TypeScript). Your best bet is to just use the built in Set for simple values or a Set library which uses deep equality (such as immutable-js), which will allow you iterate through in insertion order and enforces that all items are unique.
For the sake of giving an answer which works using the typechecker though:
It's possible to use typed conditionals to return the type as never
, thus ensuring the program doesn't compile. However, you'd need to know the values at compile time for this to be any use.
We can use a workaround for the fact TS does not have an equality operator using the technique descibed here: https://stackoverflow.com/a/53808212/7042389. We can then use that to build an array of unique types, where if one matches another its type is returned as never
- this will force a compilation error as no value can be assigned to never.
type IfNotEq<A, B, T> =
(<T>() => T extends A ? 1 : 2) extends
(<T>() => T extends B ? 1 : 2) ? never : T;
type UniqueArray2<A, B> = IfNotEq<A, B, [A, B]>;
type UniqueArray3<A, B, C> = IfNotEq<A, B, IfNotEq<B, C, IfNotEq<A, C, [A, B, C]>>>;
const xs1: UniqueArray2<"a", "b"> = ["a", "b"]; // works
const xs2: UniqueArray2<"a", "a"> = ["a", "a"]; // string is not assignable to never
const ys1: UniqueArray3<"a", "b", "c"> = ["a", "b", "c"];
const ys2: UniqueArray3<"a", "a", "b"> = ["a", "b", "c"]; // string is not assignable to never
Playground Link
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With