我试图通过将静态约束引入聊天命令来减少代码量和错误。使用名称和参数描述命令。这是我得到的:
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
从类型arguments
的Command<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);
},
});
推断CommandHandler
从CommandArguments
,我们可能不希望做相反,即ArgumentName<T[k]>
在
type CommandArguments<T> = { [k in keyof T]: ArgumentName<T[k]> };
上述方法的另一个问题是,从上面的声明,CommandArguments
只是限制了钥匙的T
,这就是为什么T
的属性值类型被推断为刚unknown
。
一个直接的解决方案是约束arguments
的类型T
,以延伸的一个目的ArgumentTypeName
,则推断handler
的args
该类型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] 删除。
我来说两句