首页 > 解决方案 > 输入接收动态参数的函数的 returnType

问题描述

我有一个接收函数,args可以键入 asstring或 as [string, Record<string, string>]

此函数返回一个对象,如果这些 args 被键入,则该对象的键是函数的 args,string如果这些 arg 被键入,则返回数组中的第一个字符串[string, Record<string, string>]。该对象的所有值都输入为string

例如 :

exampleFunction("test1", "test2", ["test3", { result: "randomstring" }], "test4");

应该返回如下类型的内容:

type tResult = {
  test1: string;
  test2: string;
  test3: string;
  test4: string;
};

此函数可以采用任意数量的 args,并且这些 args 中的任何一个都可以是string[string, Record<string, string>]

挑战在于输入 this 的 returnType exampleFunction

打字稿沙箱链接在这里

我试着用以下方式输入tExampleFunctionReturn<T>

type tExampleFunctionReturn<T extends tExampleFunctionArgs> = Record<
  T[number] extends string ? T[number] : T[number][0],
  string
>

但它不起作用。

有人可以帮帮我吗 ?谢谢您的回答。

标签: typescript

解决方案


TypeScript 编译器无法推断 的输出args.reduce(...)将是ExampleFunctionReturn<T>. 仅用于Array.prototype.reduce()模拟累加器类型在操作期间保持不变的情况。您正在逐步向对象添加属性,但编译器仅将其视为 type {},它为您传入的初始空对象推断出的类型。

试图引导编译器理解从类型{}到最终输出类型的逐渐变异可能是没有希望的。该语言可能需要microsoft/TypeScript#1213中要求的所谓的更高种类的类型才能表达这种关系,而且谁知道即使在那时推理也能起作用。但如果没有这种更高种类的类型,甚至没有一个合理的起点。

如果您只是自己计算类型并断言所讨论的值属于该类型,那么您将获得更进一步的信息,而不是试图让编译器推断类型。这是我的处理方法:

const exampleFunction = <K extends string>(
  ...args: Array<K | [K, Record<string, string>]>
) => {
  return args.reduce((acc, arg) => {
    if (typeof arg == "string") {
      return {
        ...acc,
        [arg]: "randomstring",
      };
    } else {
      return {
        ...acc,
        [arg[0]]: arg[1].result,
      };
    }
  }, {} as { [P in K]: string }); // assert here
};

请注意,我已经更改了您示例中的类型;我不再使用T对应于args其余参数类型的泛型参数。由于您要跟踪的只是预期键的文字类型,因此我改为使用泛型类型参数K表示这些键的联合。那么args数组元素的类型是K | [K, Record<string, string>]

这比从整个数组类型开始T并尝试从中提取键更容易。

它还具有K extends string向编译器提示您需要字符串文字类型的优点。不幸的是,使用您的原始类型,除非您使用断言或类似的东西,否则该值["test3", {...}]将被扩大。stringconst

无论如何,我已经断言累加器的类型等同于Record<K, string>,因此 的输出exampleFunction()是相同的类型。让我们看看它是否有效:

const result = exampleFunction(
  "test1", "test2", ["test3", { result: "randomstring" }], "test4"
);
/* const result: {
    test1: string;
    test2: string;
    test3: string;
    test4: string;
} */

console.log(result.test1.toUpperCase()) // RANDOMSTRING

看起来不错!

Playground 代码链接


推荐阅读