如何解决TS中OmitProperties提取类属性时误排除any类型属性问题
问题描述
实现从类中提取全部属性生成对应类型的功能时,借助ts-essential库提供的OmitProperties工具类型,定义type GetProperties<T> = OmitProperties<T, Function>用于剔除类的方法属性。实际测试发现该写法不仅会移除类方法,还会将所有标注为any类型的属性一并排除。
测试代码如下:
type GetProperties<T> = OmitProperties<T, Function> class Foo { foo: string = ''; bar: any | null = null; } export type FooProperties = GetProperties<Foo>; // 最终仅得到类型{ foo: string; },缺失bar属性
问题根因
OmitProperties内部通过类型兼容性判断过滤匹配目标类型的属性,而TypeScript中any是顶层兼容类型,会和所有类型(包括Function)判定为兼容,因此any类型的属性会被误判为方法属性,被错误过滤。
改进实现
通过自定义映射类型实现属性提取,单独处理any类型的边界判断,避免any的全局兼容特性干扰过滤逻辑:
// 辅助类型:精准判断类型是否为any,无其他类型误判 type IsAny<T> = 0 extends (1 & T) ? true : false; type GetClassProperties<T> = { [K in keyof T as IsAny<T[K]> extends true ? K // any类型属性直接保留 : T[K] extends Function ? never // 非any的函数类型属性过滤 : K // 其余普通属性保留 ]: T[K] };
实现逻辑说明:
- 利用
any和任意类型交叉结果仍为any的特性,通过IsAny精准识别any类型属性,不会和其他类型产生混淆 - 遍历类的所有键做条件判断:
any类型属性直接保留,函数类型(类方法)过滤,其余普通属性全部保留 - 支持保留
any | null、any | undefined等包含any的联合类型属性
验证效果
使用改进后的类型做测试:
class Foo { foo: string = ''; bar: any | null = null; sayHello() {} // 类方法 count: number = 0; rawConfig: any = {}; } export type FooProperties = GetClassProperties<Foo>; // 最终得到类型:{ foo: string; bar: any | null; count: number; rawConfig: any } // 所有非方法属性完整保留,类方法被正确剔除
注意事项:
- 涉及类型兼容性判断的工具类型,必须单独处理
any类型的边界情况,否则会因any兼容所有类型的特性出现逻辑错误 - 提取类属性的场景不建议直接使用通用的
OmitProperties实现,通用工具未针对类场景的any属性做特殊适配
内容的提问来源于stack exchange,提问作者Matthieu Riegler
相关产品推荐
相关产品推荐

