Adam Thompson
Adam Thompson

Reputation: 467

Ensure a Typescript array has a specific value

I'm building a dropdown-style component the value and options are distinct props. I'm hoping to use Typescript to ensure that the value is a valid option. While I could do this check at runtime, I feel like this is something I should be able to do in TS.

Is this possible?

interface Props<N extends number> {
    count: N,
    options: Array<N | number> // Tuples don't work here, since this can be any length
}

const Component = <N extends number>({count, options} : Props<N>) => {
  // We could do a runtime check to verify that `count` is in `options`, but I'd rather do the check earlier if possible
}

Component({count: 5, options: [1,2,3]}) // This should be an error

Upvotes: 1

Views: 219

Answers (1)

Tobias S.
Tobias S.

Reputation: 23925

The idea is to infer both the literal types of count and options into the generic types N and O. This is trivial for N, but for O we need to hint to the compiler to infer a tuple type of number literals instead of just number[]. We can achieve this by wrapping O into a variadic tuple type which looks like [...O].

To achieve the validation, we can use a conditional type to check if N is a member of O[number]. If it is not a member, the conditional resolves to never leading to the error as nothing can be assigned to never.

interface Props<N extends number, O extends readonly number[]> {
  count: N;
  options: N extends O[number] ? readonly [...O] : never;
}
const Component = <N extends number, O extends readonly number[]>({
  count,
  options,
}: Props<N, O>) => {};

This works fine, as long as the array passed as options is a tuple type.

Component({ count: 5, options: [1, 2, 3] }); // error

Component({ count: 5, options: [1, 2, 3, 5] }); // ok

Component({ count: 5, options: [] as number[] }); 
// ok, all the elements in options are number and 5 does extend number :/

If options is an array type, its elements are of type number and 5 does extend number which ultimately passes the type checking.


Playground

Upvotes: 1

Related Questions