typescript 如何使一个示例方法只接受另一个示例方法的名称?

cwtwac6a  于 11个月前  发布在  TypeScript
关注(0)|答案(3)|浏览(113)

我有一个具有一些属性和方法的对象。我如何给予它一个只接受它的另一个方法的名称的方法?
例如,考虑User类中的command方法。我们希望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`

字符串

avwztpqn

avwztpqn1#

不知道你具体想做什么,但这对你的用例有用吗?

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`);

字符串

1qczuiv0

1qczuiv02#

若要将命令方法的可接受类型限制为仅使用User方法名称,而不对其进行硬编码,可以将条件类型和Map类型组合在一起使用合并。

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'

字符串

iqih9akk

iqih9akk3#

TypeScript没有内置的KeysMatching<T, V>类型操作符来提取T类型的键,其值与microsoft/TypeScript#48992中请求的其他类型V匹配,但您可以自己实现一个适用于某些用例的类型操作符,例如:

type KeysMatching<T, V> =
  { [K in keyof T]: T[K] extends V ? K : never }[keyof T]

字符串
然后,从概念上讲,您可以将commandName的类型设置为KeysMatching<User, ()=>void>,以便它只允许零参数方法。(因为commandName的类型取决于User的类型,而User的类型又取决于command的类型,而command的类型又取决于commandName的类型)。你可以通过从键中省略"command"来避免这一点,使用Omit实用程序类型:

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


Playground链接到代码

相关问题