i need to union of all my key and method from object to a an enum
// i want that result [ 'aStore.aMethod1','aStore.aMethod2', 'bStore.bMethod1', 'bStore.bMethod2' ,''bStore.bMethod3'] sample
const objA = {
aMethod1: function (_params: string) {
console.log("obj A a method1")
return 'A1'
},
aMethod2: function (_params: string, _param2: string) {
console.log("obj A a method2")
return 'A2'
}
}
const objB = {
bMethod1: function (_params: string) {
console.log("obj b bmethod1")
return 'B1'
},
bMethod2: function (_params: string, _param2: string) {
console.log("obj B bmethod2")
return 'B2'
},
bMethod3: function (_params: string, _param2: string) {
console.log("obj B bmethod3")
return 'B3';
}
}
const rootStore = {
aStore: objA,
bStore: objB,
}
// https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html
type actionName<T> = `${string & keyof T}.${'HELP'}`;
/// how do i make typesafe here
// i want an action a list of [ 'aStore.aMethod1','aStore.aMethod2', 'bStore.bMethod1', 'bStore.bMethod2' ,''bStore.bMethod3']
// is there any way to make args type safe too.
function dynamicCall<T> (action: actionName<T>,...args:any) {
// it will call objA
const [storeName, method] = action.split('.');
const store= (rootStore as any)[storeName];
if(store&&store[method]){
(store as any)[method].apply(undefined,args)
}
}
dynamicCall<typeof rootStore>('aStore.aMethod1')
it will perfect if you can help to make an args typesafe too. Thank you
CodePudding user response:
You can use a mapped type to go through all the properties on the root type and build the paths:
type actionName<T> = {
[K in keyof T & string]: `${K}.${keyof T[K] & string}`;
}[keyof T & string]
You can also get the parameters and the return type to type check:
type ActionName<T> = {
[K in keyof T & string]: `${K}.${keyof T[K] & string}`;
}[keyof T & string]
type GetMethod<T, M> = M extends `${infer K}.${infer SubKey}` ?
T extends Record<K, Record<SubKey, infer Method extends (...a: any) => any>> ? Method: never: never;
function dynamicCall<T>(store: T) {
return <M extends ActionName<T>>(action: ActionName<T>,...args: Parameters<GetMethod<T, M>>): ReturnType<GetMethod<T, M>> => {
const [storeName, method] = action.split('.');
const store= (rootStore as any)[storeName];
if(store&&store[method]){
return (store as any)[method].apply(undefined,args)
}
throw new Error("Method not found")
}
}