TypeScript条件类型:过滤只读属性/按修饰符选取属性
如何用TypeScript过滤接口中的只读属性
当然可以做到!TypeScript的条件类型搭配映射类型修饰符,完全能帮你从接口中筛选出非只读属性,生成新的类型。下面我给你具体实现和原理说明:
方法一:先提取可写属性名,再选取属性
首先我们可以定义一个辅助类型,用来提取接口中所有**可写(非只读)**的属性名:
// 提取所有可写属性的键名 type MutableKeys<T> = { [K in keyof T]-?: { [P in K]: T[P] } extends { -readonly [P in K]: T[P] } ? K : never; }[keyof T];
然后用Pick工具类型,从原接口中选取这些可写属性:
// 原接口 interface I1 { readonly n: number; s: string } // 生成过滤后的类型I2 type I2 = Pick<I1, MutableKeys<I1>>; // 此时I2的类型等价于: // interface I2 { s: string }
方法二:直接在映射类型中过滤
如果你想更简洁一点,可以把逻辑合并到一个映射类型里:
// 直接移除所有只读属性的类型工具 type RemoveReadonly<T> = { [K in keyof T as { [P in K]: T[P] } extends { -readonly [P in K]: T[P] } ? K : never ]: T[K]; }; // 应用到你的接口上 type I2 = RemoveReadonly<I1>;
原理说明
这里的核心逻辑依赖两个TypeScript特性:
- 映射类型修饰符
-readonly:用来移除属性的readonly标记,比如{ -readonly [P in K]: T[P] }会把属性K的只读特性去掉。 - 条件类型判断:我们对比“原属性类型”和“移除只读后的属性类型”——如果两者兼容,说明这个属性本来就不是只读的(移除readonly后没有变化),就保留这个属性名;反之则是只读属性,排除掉。
需要注意的是,这个方案要求你使用TypeScript 2.8及以上版本,因为条件类型是在2.8版本引入的,映射类型修饰符也是同期支持的。
内容的提问来源于stack exchange,提问作者DanielM
相关产品推荐
相关产品推荐

