TS进阶-高级类型

171 阅读4分钟

Partial

定义

/**
 * Make all properties in T optional
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};
  • in操作符作用:遍历类型,可以理解为 for-in循环
  • keyof(索引类型查询操作符):是将一个类型映射为它所有成员名称的联合类型。
interface Pokemon {
  pikachu: string;
  squirtle: string;
  charmander: string;
}
// 使用keyof 得到所有属性的联合类型
type test = keyof Pokemon //相当于pikachu | squirtle | charmander;
所以这里 P in keyof T相当 for-in 遍历。然后加上中括号[P in keyof T]变成一个动态的索引类型
  • 外层的?操作符,让属性变成可选项,也就是遍历的每一项属性都会变成可选的
  • T[P] 索引访问操作符,相当于js里面访问对象的值

Partial的使用

将一个已知的类型每个属性都变为可选的

interface Pokemon {
  pikachu: string;
  squirtle: string;
  charmander: string;
}
// 将接口的属性都变成可选的
type test = Partial<Pokemon>;
// 相当于
type test = {
  pikachu?: string | undefined;
  squirtle?: string | undefined;
  charmander?: string | undefined;
}
//对比源码
type Partial<T> = {
    [P in keyof T]?: T[P];
};
/* 
以上面的例子解释Partial的运行
1.首先是传入Pokemon类型,所以 T类型就是Pokemon
2.keyof T:都到所有Pokemon的属性名的联合类型,也就是 pikachu | squirtle | charmander
3.P in keyof T:相当于 p in pikachu | squirtle | charmander ,遍历这个属性名形成的联合类型
4.P in keyof T]?: T[P]:最后就是每一个动态索引类型([P in keyof T]) 加上可选符号(?)给他声明为 Pokemon类型的属性值类型
*/

Required

定义

/**
 * Make all properties in T required
 */
type Required<T> = {
    [P in keyof T]-?: T[P];
};

有了上面Partial可选类型的理解,Required其实就很容易了 使用了-? 就是去掉每一个属性的可选,于是就成为了必须

Required的使用

将一个已知的类型每个属性都变为必须的

interface Pokemon {
  pikachu?: string;
  squirtle?: string;
  charmander?: string;
}
//作用就是所有属性转为必要的
type test = Required<Pokemon>;
// 相当于
type test = {
    pikachu: string;
    squirtle: string;
    charmander: string;
}

Readonly

定义

/**
 * Make all properties in T readonly
 */
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
}

使用和Required,形成一个只能访问不能操作的新类型

Readonly的使用

将一个已知的类型每个属性都变为只读的

interface Pokemon {
  pikachu: string;
  squirtle: string;
  charmander: string;
}
type test = Readonly<Pokemon>;
//相当于
type test = {
    readonly pikachu: string;
    readonly squirtle: string;
    readonly charmander: string;
}

Pick

定义

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

这里出现了extends,而在ts中extends关键字在不同场景有不同的用法


  • 表示继承
  • 表示约束
  • 表示选择
  • 表示分配

K extends keyof T这里的extends表示约束,也就是泛型约束,相当于K 是 keyof T的子集

Pick的使用

从一个已知的类型选出所需要的属性

interface Pokemon {
  pikachu: string;
  squirtle: string;
  charmander: string;
}
//从Pokemon中取出charmander,pikachu 生成一个新类型
type test = Pick<Pokemon, 'charmander' | 'pikachu'>;
//相当于
type test = {  
charmander: string;  
pikachu: string;  
}

Record

定义

/**
 * Construct a type with a set of properties K of type T
 */
type Record<K extends keyof any, T> = {
    [P in K]: T;
};
其中keyof any 返回 string number symbol 的联合类型
所以产生的新属性名的类型约束为string |number |symbol,而属性值的类型是T

Record的使用

用来定义(约束)对象的键和值

interface Pokemon { 
pikachu: string; 
squirtle: string;
charmander: string;
}
type test = Record<keyof Pokemon, keyof Pokemon>;
//相当于 
type test = {  
pikachu: keyof Pokemon;  
squirtle: keyof Pokemon;  
charmander: keyof Pokemon;  
}
//使用Record约束test类型的属性名、属性值都为为Pokemon的属性名类型

Exclude

定义

/**
 * Exclude from T those types that are assignable to U
 */
 
type Exclude<T, U> = T extends U ? never : T;

/**
 * 从`T`中剔除可以赋值给`U`的类型。
 * 这句源码相当于三元运行符,如果T属于U(T是U的子集),那么取值never,否者取值T
 * 出现了第二个extends的用法这里既可以是表示分配或者选择
 * 如果传入的T是一个联合类型就是分配,否者就表示选择
*/

Exclude的使用

Exclude<T, U> -- 从T中剔除可以赋值给U的类型。

/*
 * type Exclude<T, U> = T extends U ? never : T;
 * 对照着源码进行使用
 */

// 1.extends表示选择,三元运算符的用法的直接体现
type test = Exclude<number, string>; // 因为number 不是string的自己,所以取值为number
// 2.extends这里表示分配因为T这里对应的是number|string|symbol的联合类型,所以联合类型的每一项都要和string做运算
type test2 = Exclude<number|string|symbol, string>; // number|symbol

Extract

定义

/**
 * Extract from T those types that are assignable to U
 */
type Extract<T, U> = T extends U ? T : never;
// 从源码上看出和Exclude比结果是相反的

Extract使用

Extract<T, U> -- 提取T中可以赋值给U的类型。

type test = Extract<string | symbol, number | string | symbol>; // string|symbol

Omit

定义

/**
 * Construct a type with the properties of T except for those in type K.
 */
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
/**
 * 对于Pick<T, Exclude<keyof T, K>>  
 * 其中Exclude<keyof T, K> 获取T的联合类型中不属于K的,接着从T中选择这些不属于它的
 * 最后 K extends keyof any:在Record上有说明,所以K被约束成 number|string|sybmol的联合类型的子集
 * 总结:剔除T中的某些属性,返回一个新类型。
/**

Omit使用

`Omit<T, K>` -- 剔除`T`中的K属性

interface Pokemon {
  pikachu: string;
  squirtle: string;
  charmander: string;
}
type test = Omit<Pokemon, "pikachu">; 
/**相当于
 * type test = {
 * squirtle: string;
 * charmander: string;
} */