【问题标题】:typescript template literal type with union all method带有 union all 方法的打字稿模板文字类型
【发布时间】:2023-01-11 21:43:40
【问题描述】:

我需要将我所有的键和方法从对象联合到枚举

// 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')

playground link

如果您也可以帮助使 args 类型安全,那将是完美的。 谢谢

【问题讨论】:

  • 如果this 适合你,请告诉我

标签: typescript


【解决方案1】:

您可以使用映射类型遍历根类型的所有属性并构建路径:

type actionName<T> = {
  [K in keyof T & string]: `${K}.${keyof T[K] & string}`; 
}[keyof T & string]

Playground Link

您还可以获取参数和返回类型以进行类型检查:

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")
  }
}

Playground Link

【讨论】:

  • 嗨,谢谢你的回答。有什么方法可以使 args 类型安全,也可以使用该方法进行映射吗?示例 dynamicCall('aStore.aMethod1',需要 1 个参数是一个字符串)。谢谢
  • @Mr.Trieu 是的,你可以。发布了一个版本。
  • 非常感谢你的帮助。您的帮助为我节省了很多时间,我真的很感激。
猜你喜欢
  • 1970-01-01
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
  • 2022-11-10
  • 2021-03-24
  • 2021-11-09
  • 2016-07-24
相关资源
最近更新 更多