有没有办法获取TypeScrip对象的所有必需属性

人气:267 发布:2022-10-16 标签: reflection typescript

问题描述

有没有办法获取TypeScrip接口或对象的所有必需属性。 类似Object.getOwnPropertyDescriptors(myObject)keyof T但带有信息属性的内容是必需的/可选的

推荐答案

在运行时这是不可能的,因为属性的必需性/可选性只存在于类型脚本类型系统中,在代码实际运行时它已经erased。您可以通过decorators等添加您自己的运行时信息,但为此您需要修改生成类和对象的实际代码。因此,在给定对象或构造函数的情况下获取必需属性名称的数组是不可能的。

在设计时,可以提取类型的必需/可选键,作为keyof T的子类型。解决方案依赖于conditional types以及空对象类型{}被认为可赋值给weak type(没有必需属性的类型)这一事实。如下所示:

type RequiredKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? never : K }[keyof T];
type OptionalKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? K : never }[keyof T];

和一个用法示例:

interface SomeType {
  required: string;
  optional?: number;
  requiredButPossiblyUndefined: boolean | undefined;
}

type SomeTypeRequiredKeys = RequiredKeys<SomeType>; 
// type SomeTypeRequiredKeys = "required" | "requiredButPossiblyUndefined" 

type SomeTypeOptionalKeys = OptionalKeys<SomeType>; 
// type SomeTypeOptionalKeys = "optional" 

这不适合index signatures:

的类型
interface SomeType {
  required: string;
  optional?: number;
  requiredButPossiblyUndefined: boolean | undefined;
  [k: string]: unknown; // index signature
} 

type SomeTypeRequiredKeys = RequiredKeys<SomeType>;
// type SomeTypeRequiredKeys = never 

type SomeTypeOptionalKeys = OptionalKeys<SomeType>;
// type SomeTypeOptionalKeys = string 

不确定您的用例是否关心可索引类型。如果是这样的话,有一个更复杂的解决方案,它首先提取已知的文字键,然后检查是否需要/可选:

(编辑:以下内容已更新以解决TS4.3中的重大更改,请参阅ms/TS#44143)

type RequiredLiteralKeys<T> = keyof { [K in keyof T as string extends K ? never : number extends K ? never :
    {} extends Pick<T, K> ? never : K]: 0 }

type OptionalLiteralKeys<T> = keyof { [K in keyof T as string extends K ? never : number extends K ? never :
    {} extends Pick<T, K> ? K : never]: 0 }

type IndexKeys<T> = string extends keyof T ? string : number extends keyof T ? number : never;

这将导致:

type SomeTypeRequiredKeys = RequiredLiteralKeys<SomeType>;
// type SomeTypeRequiredKeys = "required" | "requiredButPossiblyUndefined" 

type SomeTypeOptionalKeys = OptionalLiteralKeys<SomeType>; 
// type SomeTypeOptionalKeys = "optional" 

type SomeTypeIndexKeys = IndexKeys<SomeType>;
// type SomeTypeIndexKeys = string 

970