如何用TypeScript仅保留Angular组件中带@Input装饰器的成员类型?
提取Angular组件中带@Input装饰器的成员类型
可行,但TypeScript纯类型系统无法直接识别装饰器标记,需要结合手动标记或Angular运行时元数据实现,以下是两种方案:
方案一:手动标记+条件类型
通过给@Input属性添加标记类型,再用条件类型筛选出目标属性:
// 定义标记类型,用于标识Input属性 type InputMarker = { __isInput?: never }; // 复用Angular的@Input装饰器,仅在属性类型中添加标记 export class MyComponent { @Input() public includeMe: string & InputMarker; public excludeMe: string; } // 筛选带标记的属性 type ExtractInputProps<T> = { [K in keyof T as T[K] extends InputMarker ? K : never]: T[K] }; // 清理标记类型,得到纯净的属性类型 type CleanInputProps<T> = { [K in keyof ExtractInputProps<T>]: T[K] extends infer U & InputMarker ? U : T[K] }; // 使用示例 type MyTypedComponent = CleanInputProps<MyComponent>; // 最终类型:{ includeMe: string }
方案二:利用Angular元数据+泛型
Angular的@Input会在组件类上注入元数据,通过运行时读取元数据结合泛型提取类型:
import { ComponentFactoryResolver, ReflectiveInjector, Input } from '@angular/core'; export class MyComponent { @Input() public includeMe: string; public excludeMe: string; } // 运行时函数:提取组件的Input属性名 function getInputKeys<T>(component: new () => T): (keyof T)[] { const injector = ReflectiveInjector.resolveAndCreate([]); const factory = injector.get(ComponentFactoryResolver).resolveComponentFactory(component); return factory.inputs.map(item => item.propName as keyof T); } // 基于提取的属性名生成目标类型 type ExtractInputProps<T> = Pick<T, ReturnType<typeof getInputKeys<T>>[number]>; // 使用示例 type MyTypedComponent = ExtractInputProps<MyComponent>; // 最终类型:{ includeMe: string }
方案对比
- 方案一纯类型层面处理,无需依赖运行时,但需要手动给Input属性添加标记,适合小型项目或静态场景;
- 方案二自动读取Angular元数据,无需手动标记,但依赖Angular运行时环境,适合大型Angular项目的动态场景;
内容的提问来源于stack exchange,提问作者Martin Nielsen
相关产品推荐
相关产品推荐

