目录
将部分属性变为可选属性 根据值的类型 反选 key 写法一:基础原理写法,使用不同的内置类型,Pick 和 Omit 写法二:基础原理写法,使用 Pick 内置类型 + 传参的方式 写法三:使用映射条件做双重映射 求对象的交集 ObjectInter 求对象的差集 ObjectDiff 求对象的并集 ObjectMerge 求对象的补集 ObjectComp 重写对象类型 Overwrite上文中介绍了 对象操作的内置类型的使用,本文介绍几个基于内置类型,扩展的自定义类型, (类型名称自定义的)
将部分属性变为可选属性
实现思路:先将 name 属性挑出来变为可选的 & 除了 name 属性的
// 有时处理类型之后,对象类型结构不明显。只是简单做一个映射,并未其他意义。 type Compute<T extends object> = { [K in keyof T]: T[K]; // 映射 }; interface Person { name: string; age: number; address: string; } // 先将name属性挑出来变为可选的 & 除了name属性的 // Partial<Pick<T, K>> & & Omit<T, K> type PartialPropsOption<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>; type x1 = PartialPropsOption<Person, "name">; type x2 = Compute<PartialPropsOption<Person, "name">>; // 使用Compute包一层可以看清楚结构,不包也可以
根据值的类型 反选 key
之前的常见做法都是用过 key 值来获取属性,反之,如果根据值的类型 反选 key?
写法一:基础原理写法,使用不同的内置类型,Pick 和 Omit
定义一个接口 Person。通过 不同的内置类型 ,实现 挑选 值类型为string的keys 和 过滤 值类型为string的keys
interface Person { name: string; age: number; address: string; } // 判断两个类型是否相等 type isEqual<T, U, Success, Fail> = [T] extends [U] ? ([U] extends [T] ? Success : Fail) : Fail; type ExtractKeysByValueType<T, U> = { [K in keyof T]: isEqual<T[K], U, K, never>; }[keyof T]; // 找到需要的属性 name | address **注:联合类型中没有never type PickKeysByValue<T, U> = Pick<T, ExtractKeysByValueType<T, U>>; type PickedKeys = PickKeysByValue<Person, string>; // 挑选 值类型为string的keys 返回 name address type OmitKeysByValue<T, U> = Omit<T, ExtractKeysByValueType<T, U>>; type OmitedKeys = OmitKeysByValue<Person, string>; // 过滤 值类型为string的keys 返回 age
写法二:基础原理写法,使用 Pick 内置类型 + 传参的方式
interface Person { name: string; age: number; address: string; } // 判断两个类型是否相等 type isEqual<T, U, Success, Fail> = [T] extends [U] ? ([U] extends [T] ? Success : Fail) : Fail; type ExtractKeysByValueType<T, U, O = false> = { [K in keyof T]: isEqual<T[K], U, isEqual<O, true, never, K>, isEqual<O, true, K, never>>; }[keyof T]; // 找到需要的属性 name | address **注:联合类型中没有never type PickKeysByValue<T, U> = Pick<T, ExtractKeysByValueType<T, U>>; type PickedKeys = PickKeysByValue<Person, string>; // 挑选 值类型为string的keys 返回 name address type OmitKeysByValue<T, U> = Pick<T, ExtractKeysByValueType<T, U, true>>; type OmitedKeys = OmitKeysByValue<Person, string>; // 过滤 值类型为string的keys 返回 age
写法三:使用映射条件做双重映射
interface Person { name: string; age: number; address: string; } type PickKeysByValue<T extends object, U> = { // [K in keyof T as `a_${K & string}`]: T[K]; // 使用模板字符串 重命名 // as 语法 映射成一个新的变量 [K in keyof T as T[K] extends U ? K : never]: T[K]; }; type PickKeysByAs = PickKeysByValue<Person, string>; // 挑选 值类型为string的keys 返回 name address
求对象的交集 ObjectInter
交集:指的是类型中的 属性 , 属性 , 属性 ,即存在于 A 中,又存在于 B 中,属性的类型可以不同,取交集后者类型,
type A = { name: string; age: number; address: string; }; type B = { name: string; male: boolean; address: number; }; // 返回的是联合类型 name | address type ObjectInter<T extends object, U extends object> = Pick<U, Extract<keyof T, keyof U>>; type X1 = ObjectInter<A, B>; // 从B中取A,address类型取B中的类型 number
求对象的差集 ObjectDiff
算一下 B - A,使用内置类型组合: Omit + Extract == Pick + Exclude
组合的写法比较多种,只要可以实现就可以,需要注意的是 谁-谁 ,就是从哪个对象中挑选
type A = { name: string; age: number; address: string; }; type B = { name: string; male: boolean; address: number; }; type ObjectDiff<T extends object, U extends object> = Omit<U, Extract<keyof T, keyof U>>; type X2 = ObjectDiff<A, B>; // B - A = male: boolean; type ObjectDiff2<T extends object, U extends object> = Pick<T, Exclude<keyof T, keyof U>>; type X3 = ObjectDiff2<A, B>; // A - B = age: number; type OmitDiff<T extends object, U extends Object> = Omit<T, keyof U>; type X4 = OmitDiff<A, B>; // A - B = age: number;
求对象的并集 ObjectMerge
希望最终得到的结果是 type X7 = { age: number; name: string; address: number; male: boolean;}
实现思路:先找出 A - B的差 集,再 & B
type A = { name: string; age: number; address: string; }; type B = { name: string; address: number; male: boolean; }; type Compute<T extends object> = { [K in keyof T]: T[K]; // 只是做了映射,为了显示类型结果 }; type ObjectMerge<T extends object, U extends object> = Omit<T, keyof U> & U; type X5 = Compute<ObjectMerge<A, B>>;
求对象的补集 ObjectComp
补集:存在于 A 中,不存在于 B 中,属性相差。互补, 注意:双方得存在父子关系,才能互补 也就是 B 是 A 的子类型
type A = { name: string; age: number; address: string; }; type B = { name: string; address: string; }; // 类型“B” 需要满足约束 “A”。 type ObjectComp<T extends object, U extends T> = Omit<U, Extract<keyof T, keyof U>>; type X6 = ObjectComp<B, A>; // age: number;
重写对象类型 Overwrite
使用 B 重写 A 中相同的属性,案例中就是 使用 address: string => address: number ,其他不变
希望最终得到的结果是 A=> { name: string; age: number; address: number }
实现思路:先找出交集,在找差集,利用上边已经实现的代码
type A = { name: string; age: number; address: string; }; type B = { name: string; address: number; male: boolean; }; type Compute<T extends object> = { [K in keyof T]: T[K]; // 只是做了映射,为了显示类型结果 }; type Overwrite<T extends object, U extends object> = ObjectInter<A, B> & ObjectDiff2<A, B>; type X7 = Compute<Overwrite<A, B>>;
查看更多关于TypeScript 学习笔记 — 自定义类型:部分属性可选,反选 key,求对象交差并补集等(十三的详细内容...