Reputation: 2057
Is there a way to write a function such that its return type is the union of values of an array.
Something like,
function within(values: string[]) {
return (val: any): <union of values> => {
if(!values.include(val)) throw new Error('Not allowed')
return val
}
}
Now ReturnType<within(['a', 'b'])>
would be 'a' | 'b'
.
Upvotes: 0
Views: 276
Reputation: 8340
In complement to this answer.
For inline cases you can simplify call semantics using variadic tuple types:
function within<T extends string[]>(values: readonly [...T]) {
return (val: unknown) => {
if(!(values as readonly unknown[]).includes(val)) throw new Error('Not allowed')
return val as T[number];
};
}
const arr = ['a', 'b'] as const; // still have to annotate `as const` to prevent widening
const r1 = within(arr)('a'); // type of r is 'a' | 'b'
const r2 = within(['a', 'b'])('b'); // typescript infers readonly automatically; r2 ~ 'a' | 'b'
Upvotes: 2
Reputation: 370689
Make the function generic.
function within<T extends Array<string>>(values: T) {
return (val: unknown) => {
if(!(values as unknown[]).includes(val)) throw new Error('Not allowed')
return val as T[number];
};
}
const arr = ['a', 'b'] as ['a', 'b']; // prevent automatic widening to string[]
const r = within(arr)('a');
// type of r is 'a' | 'b'
Note that since .includes
has type problems, you need to do something to get around it, such as asserting that the values
is unknown[]
.
Upvotes: 2