typescript 如何正确地键入一个通过其他几个对象Map回来的函数?

nc1teljy  于 2023-02-05  发布在  TypeScript
关注(0)|答案(1)|浏览(107)

编辑

requestedFunctionAlias是动态的。
例如,

const getFn = ({ requestedFunctionAlias }) => {
    return FUNCTIONS_MATRIX[FUNCTION_ALIASES[requestedFunctionAlias]];
}

const fn = getFn({ requestedFunctionAlias: 'a1' });

fn({ age: 30 })

假设如下,

const myFunction1 = ({ name }: { name: string }) => console.log('name', name);
const myFunction2 = ({ age }: { age: number }) => console.log('age', age);
const myFunction3 = ({ hobbies }: { hobbies: string[] }) => console.log('hobbies', hobbies);

const FUNCTION_ALIASES = {
  a1: 'myFunction1',
  a2: 'myFunction2',
  a3: 'myFunction3',
};

const FUNCTIONS_MAP = {
  myFunction1: 'a1',
  myFunction2: 'a2',
  myFunction3: 'a3',
};

const FUNCTIONS_MATRIX = {
  [FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction1]]: myFunction1,
// ^^^ Element implicitly has an 'any' type 
  [FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction2]]: myFunction2,
// ^^^ Element implicitly has an 'any' type 
  [FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction3]]: myFunction3,
// ^^^ Element implicitly has an 'any' type 
};

const requestedFunctionAlias: string = 'a1';

const fn = FUNCTIONS_MATRIX[FUNCTION_ALIASES[requestedFunctionAlias]];
//                          ^^^^ Element implicitly has an 'any' type

fn({ name: 'Michael!' });
//  ^^^^^^ Property 'age' is missing in type '{ name: string; }' but required in type '{ age: number; }'

我可以像这样解决其中的一些错误,

const FUNCTIONS_MATRIX = {
  [FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction1 as keyof typeof FUNCTION_ALIASES]]: myFunction1,
  [FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction2 as keyof typeof FUNCTION_ALIASES]]: myFunction2,
  [FUNCTION_ALIASES[FUNCTIONS_MAP.myFunction3 as keyof typeof FUNCTION_ALIASES]]: myFunction3,
};

const fn = FUNCTIONS_MATRIX[FUNCTION_ALIASES[requestedFunctionAlias as keyof typeof FUNCTION_ALIASES]];

但这看起来很混乱,而且仍然不能解决fn({ name: 'Michael!' });处的错误。
我在这里能做什么?

weylhg0b

weylhg0b1#

首先声明FUNCTION_ALIASESFUNCTIONS_MAPas const,告诉typescript它们的类型比key: string窄。

const FUNCTION_ALIASES = {
  a1: "myFunction1",
  a2: "myFunction2",
  a3: "myFunction3",
} as const;

const FUNCTIONS_MAP = {
  myFunction1: "a1",
  myFunction2: "a2",
  myFunction3: "a3",
} as const;

然后从requestedFunctionAlias中删除类型声明string,因为它丢失了类型信息-它的类型是literal "a1",而typescript需要它,以便在类型检查时确切地知道哪个函数将被返回:

const requestedFunctionAlias = "a1";

编辑:使用函数重载,你可以处理动态参数:

const myFunction1 = ({ name }: { name: string }) => console.log("name", name);
const myFunction2 = ({ age }: { age: number }) => console.log("age", age);
const myFunction3 = ({ hobbies }: { hobbies: string[] }) =>
  console.log("hobbies", hobbies);

function myFunction(which: "a1", arg: Parameters<typeof myFunction1>[0]): void;
function myFunction(which: "a2", arg: Parameters<typeof myFunction2>[0]): void;
function myFunction(which: "a3", arg: Parameters<typeof myFunction3>[0]): void;
function myFunction(
  which: "a1" | "a2" | "a3",
  arg: any
) {
  switch (which) {
    case "a1":
      return myFunction1(arg);

    case "a2":
      return myFunction2(arg);

    case "a3":
      return myFunction3(arg);

    default:
      break;
  }
}

myFunction("a1", { name: "Michael!" });

相关问题