Asur
Asur

Reputation: 2057

Typescript function whose return type is union of values in array

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

Answers (2)

aleksxor
aleksxor

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'

playground link

Upvotes: 2

CertainPerformance
CertainPerformance

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

Related Questions