TypeScript:创建类型,根据其值类型删除接口/类的属性
Posted
技术标签:
【中文标题】TypeScript:创建类型,根据其值类型删除接口/类的属性【英文标题】:TypeScript: Create type that removes properties of an interface/class based on their value-types 【发布时间】: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<keyof MethodsOf<Person>>
或(keyof MethodsOf<Person>)[]
那里。注意优先级,keyof MethodsOf<Person>[]
在数组上应用keyof
。
【参考方案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;
然后用它来实现MethodKeys
和Methods
:
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
【讨论】:
以上是关于TypeScript:创建类型,根据其值类型删除接口/类的属性的主要内容,如果未能解决你的问题,请参考以下文章
TypeScript:删除索引签名而不隐式出现“任何”类型错误
TypeScript:你能根据函数的参数定义一个返回类型结构吗?