将动态对象映射到打字稿函数参数

Mapping a dynamic object to typescript function params

我正在尝试制作一个列表(下面的示例)并将其映射到函数的参数。 我想象参数是一个对象,其键与参数名称匹配,值是每个参数的选项(无论是必需的还是更重要的,什么类型)。

interface Command<T> {        // Theese are the parts that I'm curious about, 
  args: T,                    // idk if its even possible, or if there's another solution.
  run(...args: T) {           // 
    
  }
}

const Arguments = {
  name: {
    type: "string",
    required: true,
  },
  duration: {
    type: "number",
    required: false,
  }
};

const cmd: Command<typeof Arguments> = {
  args: Arguments,
  run(name, duration) {
    console.log(`banned ${name} for ${duration ?? "forever"}`);
  }
}

如果可能或者您对如何实现这一点有任何想法,请告诉我,因为我已经为此苦苦挣扎了好几天。

由于您想按原样推断对象的类型,我们将使用 as const 断言。

然后我们需要创建一个 ObjectToParams<T> 类型别名,它允许我们进行此转换并为输出对象实现所需的约束格式 assignable

const Arguments = {
  name: {
    type: "string",
    required: true,
  },
  duration: {
    type: "number",
    required: false,
  }
} as const;


type ObjectToParams<T extends { [k: string]: { type: string } }> 
= { args: T, run: (args: { [k in keyof T]: T[k]["type"] }) => void }



const cmd: ObjectToParams<typeof Arguments> = {
  args: Arguments, // Get inference for Arguments

  run({name, duration}) {
    console.log(`banned ${name} for ${duration ?? "forever"}`);
  }
}

Code Playground

你需要更多的魔法才能做到这一点。首先是描述参数对象类型的类型:

type ArgsObject = Record<string, { type: "string" | "number" | "boolean"; required: boolean }>;

然后我们将字符串映射到它们的实际类型(即“字符串”到 string):

type MapToType = {
    string: string;
    number: number;
    boolean: boolean;
    // more if needed
};

最后我们映射参数并获取每个参数的类型:

type ArgsToContext<Args extends ArgsObject> = {
    [K in keyof Args]: MapToType[Args[K]["type"]] | IsOptional<Args[K]>;
};

其中 IsOptional 定义为:

type IsOptional<T extends ArgsObject[string]> = T["required"] extends true ? never : undefined;

这是因为如果需要,它给我们 never,而 Type | never 总是 Type。但是,如果不需要(可选),它会为我们提供 undefined,从而得到所需的 Type | undefined

这里 playground 展示了这一点。