根据对象的属性值获取对象类型

弗拉德

我试图通过将静态约束引入聊天命令来减少代码量和错误。使用名称和参数描述命令。这是我得到的:

type ArgumentTypeName = 'string' | 'number' | 'user';
type CommandArguments<T> = { [k in keyof T]: ArgumentTypeName };
type CommandHandler<T> = (args: T) => void;

type Command<T> = {
  name: string;
  arguments: CommandArguments<T>;
  handler: CommandHandler<T>;
}

我无法弄清楚如何获得T从类型argumentsCommand<T>,所以它可以正确地影响handler到目前为止,我的键类型正确,但是所有值都是unknown像这样:

arguments = { arg1: 'string' }
// handler: (args: { arg1: unknown }) => void

我还尝试进行约束arguments,以为如果我不指定T,它将根据进行推断arguments,但这没有用:

type ArgumentName<T> = 
  T extends string ? 'string' :
  T extends number ? 'number' :
  T extends User ? 'user' :
  never;

type CommandArguments<T> = { [k in keyof T]: ArgumentName<T[k]> };
type CommandHandler<T> = (args: T) => void;

type Command<T> = {
  name: string;
  arguments: CommandArguments<T>;
  handler: CommandHandler<T>;
}

我如何T根据其属性推论反向CommandArguments<T>
所以我得到CommandArguments<T>→交通T→交通CommandHandler<T>
还是有我没想到的其他方法?

编辑:使用此代码示例:

/*
In another file:
  const commands: Command<any>[] = [];
  export function createCommand<T>(cmd: Command<T>) {
    commands.push(cmd);
  }
*/

createCommand({
  name: 'add',
  arguments: {
    a: 'number',
    b: 'number'
  },
  handler: (args) => {
    // (parameter) args: { a: unknown; b: unknown; }
    // Error: Object is of type 'unknown'. ts(2571)
    console.log(args.a + args.b);
  },
});
富国

推断CommandHandlerCommandArguments,我们可能不希望做相反,即ArgumentName<T[k]>

type CommandArguments<T> = { [k in keyof T]: ArgumentName<T[k]> };

上述方法的另一个问题是,从上面的声明,CommandArguments只是限制了钥匙T,这就是为什么T的属性类型被推断为刚unknown

一个直接的解决方案是约束arguments的类型T,以延伸的一个目的ArgumentTypeName,则推断handlerargs该类型T在这里我们需要使用T extends CommandArguments而不是CommandArguments为了捕获实际的使用类型。

declare interface User{};
type ArgumentType<T> =
  T extends 'string' ? string :
  T extends 'number' ? number :
  T extends 'user'   ? User   :
  never;

type ArgumentTypeName = 'string' | 'number' | 'user';
type CommandArguments = { [k: string]: ArgumentTypeName };
type CommandHandler<T> = (args: { [k in keyof T]: ArgumentType<T[k]>}) => void;

type Command<T extends CommandArguments> = {
  name: string;
  arguments: T;
  handler: CommandHandler<T>;
}

const commands: Command<any>[] = [];
export function createCommand<T extends CommandArguments>(cmd: Command<T>) {
  commands.push(cmd);
}

createCommand({
  name: 'add',
  arguments: {
    a: 'number',
    b: 'string',
    c: 'user',
  },
  handler: (args) => {
    // (parameter) args: { a: number; b: string; c: User }
    console.log(args.a.toPrecision(2) + args.b.padStart(30));
  },
});

游乐场链接

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章