Skip to content

Instantly share code, notes, and snippets.

@Schniz
Created December 9, 2020 14:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Schniz/5a9a6613f2a55642930bbb4c78da472a to your computer and use it in GitHub Desktop.
Save Schniz/5a9a6613f2a55642930bbb4c78da472a to your computer and use it in GitHub Desktop.
type IndexableKeys<T> = { [key in keyof T]: T[key] extends string ? key : never }[keyof T];
function matcher<T>(): <K extends IndexableKeys<T>>(key: K) => <R>(
legs: {
[key in Extract<T[Extract<K, keyof T>], string>]: (arg: T & Record<K, key>) => R
}
) => (t: T) => R {
return (key) => (legs) => (t) => {
const state = t[key];
return legs[state](t);
}
}
function matcherOptional<T>(): <K extends IndexableKeys<T>>(key: K) => <R>(
legs: {
[key in Extract<T[Extract<K, keyof T>], string>]?: (arg: T & Record<K, key>) => R
}
) => (t: T) => R | undefined {
return (key) => (legs) => (t) => {
const state = t[key];
return legs[state]?.(t);
}
}
type TypeWithStateAndAction = { action: 'kaki', state: 'hello', payload: { number: number } } | { action: 'pipi', state: 'goodbye', payload2: { string: string } };
const byAction = matcher<TypeWithStateAndAction>()("action")({
kaki({ payload }) {
return payload.number + 10;
},
pipi({ payload2 }) {
return payload2.string.length;
}
});
const byState = matcher<TypeWithStateAndAction>()("state")({
goodbye({ payload2 }) {
return `payload: ${payload2.string}`;
},
hello({ payload }) {
return `number: ${payload.number}`;
}
});
const byStateOptional = matcherOptional<TypeWithStateAndAction>()("state")({
goodbye({ payload2 }) {
return `payload: ${payload2.string}`;
},
});
console.log(byAction({ action: "kaki", payload: { number: 10 }, state: 'hello' }));
console.log(byState({ action: "kaki", payload: { number: 10 }, state: 'hello' }));
console.log(byStateOptional({ action: "kaki", payload: { number: 10 }, state: 'hello' }));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment