【问题标题】:TypeScript: Create type that removes properties of an interface/class based on their value-typesTypeScript:创建类型,根据其值类型删除接口/类的属性
【发布时间】:2021-12-20 05:27:15
【问题描述】:

想象一下班级:

class Person {
  name = "Ann";
  sleep() { /*...*/ }
  eat() { /*...*/ }
}

现在我想创建一个只提取方法的类型:

// should work:
const personMethods: MethodsOf<Person> = { sleep() {}, eat() {} };
const names: keyof MethodsOf<Person>[] = ['sleep', 'eat'];
// should fail:
const personMethods: MethodsOf<Person> = { notAPersonMethod() {} };
const names: keyof MethodsOf<Person>[] = ['not', 'existing', 'methods'];

我在 typescript 文档中找不到任何内容,到目前为止我的尝试都失败了。我试过了:

type MethodKeys<
  Type extends object,
  Key extends keyof Type,
> = keyof Record<Type[Key] extends AnyFn ? Key : never, any>;

type Methods<Type extends object> = {
  [Property in MethodKeys<Type, keyof Type>]: Type[Property];
};

const test: MethodKeys<Person> = 'name'; // works, but shouldn't :(
const test2: Partial<Methods<Person>> = { name: 'Ann' }, // works too :/

感谢您的帮助!

【问题讨论】:

  • 我想你的意思是Array&lt;keyof MethodsOf&lt;Person&gt;&gt;(keyof MethodsOf&lt;Person&gt;)[] 那里。注意优先级,keyof MethodsOf&lt;Person&gt;[] 在数组上应用keyof

标签: typescript types mapped-types conditional-types


【解决方案1】:

您所需要的只是一种类型,它可以返回给定类/接口的方法名称。您可以使用mapped type 创建一个对象类型,其中每个值代表每个方法名称。然后,您可以索引该对象类型以获取其值类型 - 这将产生所有方法名称的联合。

type MethodKeys<T> = {
    [K in keyof T]: T[K] extends (...x: any) => any ? K : never;
}[keyof T]

现在,您可以使用 Pick 从您的类/接口中选择这些方法键。

type MethodsOf<T> = Pick<T, MethodKeys<T>>;

并且您给定的测试用例可以正常工作-

// works
const personMethods: MethodsOf<Person> = { sleep() {}, eat() {} };
const names: Array<keyof MethodsOf<Person>> = ['sleep', 'eat'];

const personMethods1: MethodsOf<Person> = { notAPersonMethod() {} };
// ^ Type '{ notAPersonMethod(): void; }' is not assignable to type 'MethodsOf<Person>'.
const names1: Array<keyof MethodsOf<Person>> = ['not', 'existing', 'methods'];
// ^ Type '"not"' is not assignable to type 'MethodKeys<Person>'.
// ...and more

查看playground

【讨论】:

    【解决方案2】:

    除了@Chase 的解决方案,您还可以使用distributive conditional types 来过滤掉具有函数值的键:

    type MethodHelper<T, K extends keyof T> = K extends any
        ? T[K] extends Function ? K
        : never : never;
    

    然后用它来实现MethodKeysMethods

    type MethodKeys<T> = MethodHelper<T, keyof T>;
    type Methods<T> = {
        [K in MethodKeys<T>]: T[K]
    };
    
    
    const test: MethodKeys<Person> = 'name'; // doesn't work
    const test2: MethodKeys<Person> = 'sleep'; // does work
    const test3: Partial<Methods<Person>> = { name: 'Ann' }; // doesn't work
    const test4: Partial<Methods<Person>> = { sleep() {} }; // does work
    

    Playground link

    【讨论】:

      猜你喜欢
      • 2021-06-28
      • 1970-01-01
      • 2020-06-16
      • 1970-01-01
      • 1970-01-01
      • 2020-01-13
      • 1970-01-01
      • 2021-07-09
      • 2022-12-18
      相关资源
      最近更新 更多