提问人:RobertAKARobin 提问时间:11/17/2023 更新时间:11/17/2023 访问量:51
如何使一个实例方法只接受另一个实例方法的名称?
How to make an instance method accept only the name of another instance method?
问:
我有一个具有一些属性和方法的对象。如何给它一个只接受另一个方法名称的方法?
例如,考虑此类中的方法。我们想接受另一个方法的名称。使用 将可接受的类型缩小到属性名称;我们如何进一步缩小到方法名称,而不对它们进行硬编码?command
User
command
keyof this
User
User
class User {
nameFirst: string;
nameLast: string;
command(commandName: keyof this) {
this[commandName].call(this);
}
sink() {}
swim() {}
}
const alice = new User();
alice.command(`swim`); // Accepts `nameFirst` | `nameLast` | `command` | `sink` | `swim`; we want it to accept only `sink` and `swim`
答:
1赞
sajib
11/17/2023
#1
若要将命令方法的可接受类型缩小到仅用户方法名称而不对其进行硬编码,可以将条件类型和映射类型组合在一起。
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
}[keyof T];
class User {
nameFirst: string;
nameLast: string;
command(commandName: FunctionPropertyNames<User>) {
this[commandName].call(this);
}
sink() {
console.log('Sink');
}
swim() {
console.log('Swim');
}
}
const alice = new User();
alice.command('swim'); // This is now restricted to 'sink' and 'swim'
评论
0赞
jcalz
11/17/2023
“这现在仅限于'下沉'和'游泳'” 不完全是,它也允许"command"
0赞
jcalz
11/17/2023
#2
TypeScript 没有内置的类型运算符来提取其值与某个其他类型匹配的类型的键,如 microsoft/TypeScript#48992 中的要求,但您可以自己实现一个适用于某些用例的运算符,例如:KeysMatching<T, V>
T
V
type KeysMatching<T, V> =
{ [K in keyof T]: T[K] extends V ? K : never }[keyof T]
然后,从概念上讲,您将创建类型,以便它只允许零参数方法。但这将导致循环性警告(因为 的类型取决于 which 的类型取决于 which 的类型取决于 的类型 取决于 的类型 )。您可以通过使用 Omit
实用程序类型省略要允许的键来规避此问题:commandName
KeysMatching<User, ()=>void>
commandName
User
command
commandName
"command"
class User {
nameFirst: string = "";
nameLast: string = "";
command(commandName: KeysMatching<Omit<User, "command">, () => void>) {
this[commandName].call(this);
}
sink() { }
swim() { }
needsParam(x: string) { console.log(x.toUpperCase()) }
}
const alice = new User();
alice.command("swim")
alice.command("sink");
alice.command("nameFirst"); // error, not accepted
alice.command("needsParam"); // error, not accepted
0赞
enticedcode
11/17/2023
#3
不确定您具体想做什么,但这适用于您的用例吗?
class User {
nameFirst: string;
nameLast: string;
command(commandName: keyof this) {
if (typeof this[commandName] === 'function') {
this[commandName].call(this);
}
else {
return
}
}
sink() {}
swim() {}
}
const alice = new User();
alice.command(`swim`);
评论
command("command")
command("constructor")
interface UserCommands
class User implements UserCommands
(commandName: keyof UserCommands)