'How to convert inferred String Tuple to String Union in Typescript Typings?

Goal

I am trying to make something like this:

createTaskDispatcher(["spare","not_spare"],(context,payload,dispatch)=>{
if(payload.spare){
   //do something here
   //dispatch ==>  Dispatch<Actions>= (action:Actions)=>void;
   dispatch("spare");//here should be Dispatch<"spare"|"not_spare">
}
else{
  //do something here
  dispatch("not_spare")
}
})

Things I'm Trying

I'm trying make it with these code below:

export type Dispatch<ActionType> = (action: ActionType) => void;
type ArrayRetreiver<A> = A extends Array<infer W> ? W : never;
export type ArrayToDispatch<A> = A extends string[]?Dispatch<ArrayRetreiver<A>>:never;
function createTaskDispatcher<P, U,C>( conditionList:U,dispatcher: (ctx: C, payload: P, dispath: ArrayToDispatch<U>) => void) {
  ....
}

But I get the dispatch method's parameter is string.

//the dispatch parameter: (parameter) dispatch: Dispatch<string>
let spareCheck = createTaskDispatcher( ["spare","not_spare"],(ctx, payload, dispatch) => {
});

So I use spare|not_spare like string to replace the array parameter.

export type Dispatch<ActionType> = (action: ActionType) => void;
type SplitString<S, Separater extends string = "|", AL = never> = S extends `${infer A}${Separater}${infer Rest}` ? SplitString<Rest, Separater, AL | A> : S | AL;
function createTaskDispatcher<C, P, U extends string>(conditionList: U, dispatcher: (ctx: C, payload: P, dispath: Dispatch<SplitString<U>>) => void) {
}

But I still want to know how to implement my first idea.

Summary

In a nutshell, I want to destruct the string array/tuple into string union, And the union will be the second callback's dispatch parameter's input type.



Solution 1:[1]

You can use as const to accomplish that.

type Dispatch<ActionType> = (action: ActionType) => void;
function createTaskDispatcher<ActionType, P, C>(
  conditionList: readonly ActionType[],
  dispatcher: (ctx: C, payload: P, dispatch: Dispatch<ActionType>) => void
) {}

const actionTypes = ['spare', 'not_spare'] as const;
createTaskDispatcher(actionTypes, (ctx, payload, dispatch) => {
  dispatch('not_spare')
})

Note I removed ArrayRetriever because TS has built-in support to accomplish what you were trying to do.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Amiratak88