typeScript 泛型
/**
* typeScript 学习5 泛型
* 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
* 泛型变量: <泛型变量1, ...>
* * 常用的几个命名含义:
* * T 代表类型(type),
* * K 代表对象中的键类型(Key),
* * V 代表对象中的值类型(Value),
* * E 代表元素类型(Element) ,
* * U
* 泛型接口: interface 接口名<泛型变量1 [extends 类型 | keyof 类型],....> {}
* 泛型类: class 类名 <泛型变量1 [extends 类型 | keyof 类型], ...>
* 泛型约束:
* * extends 关键字: 用于类型的继承或者条件判断,当与三目运算符(?:)使用的时候是条件判断;其他情况都是继承
* * 继承/扩展类型: 继承父类的方法和属性,扩展用于接口继承
* * 泛型约束:
* * * <U extends T> U 必须满足 T // 可以理解为继承 U 继承了 T
* * * keyof关键字: <T, U exindes keyof T> U 必须属于T的
* * 条件类型与高阶类型: 可以用来判断一个类型是否是分配给另一个类型的
* * * A extends B ? 'x' : 'y', 此处是分配 要求 A 中拥有 B 中所有的约束 如果满足 返回 x 否则返回 y
* * * 分配条件类型: 对于使用 extends 关键字的条件类型(三元),如果 extends 前面的参数是一个泛型,
* 且传入这个参数的是一个联合类型,那么则将联合类型拆开分别匹配(分配律) 然后将结果联合返回(返回值是一个联合类型)
* * * never是特殊的, "never被认为是空的联合类型", 但是因为没有满足联合项可以分配, 所以根本不会执行分配,会返回原值 never
* * * 防止条件判断中的分配: 将泛型参数用 [] 括起来, 这样传入的参数将作为一个整体
* 索引类型:
* * 索引类型的查询操作符: keyof T 表示类型T的所有公共属性的字面量的联合类型示
* * 索引访问操作符:T[K] 表示对象T的属性K所代表的类型
* 映射类型: [P in 需要被遍历的类型]: 返回值类
* * ?: 可选属性
* * -: 移除
* * readonly: 只读 readonly [P in T]: P
* 预定义的有条件类型
* 变量?.属性或方法: 相当于 三元运算 判断这个变量中这个属性是否为空或未定义 obj?. y 意思为 x可能为 null,undefined
*/
/**
* extends 关键字
*/
type Human = { name: string; occupation: string; }
type Duck = { name: string; }
// 验证 Duck 是否满足 Human 中的所有约束 如果满足返回 yes 不满足返回 no
type Bool = Duck extends Human ? 'yes' : 'no'; // Bool => 'no'
type A1 = 'x' extends 'x' ? string : number; // A1 => string
type A2 = 'x' | 'y' extends 'x' ? string : number; // A2 => number
// 因为此处 extends 条件判断 使用了泛型而且没设置条件阻断 所以但 传过来的 类型是 联合类型的时候,
// 会将联合类型拆开 分别匹配然后将结果重新组合成联合类型 返回
type P<T> = T extends 'x' ? string : number;
type A3 = P<'x' | 'y'>; // string | number
type A4 = never extends 'x' ? string : number; // string
// never被认为是空的联合类型但是因为没有满足联合项可以分配, 所以不会执行会直接返回原值 never
type A5 = P<never>; // never
// 防止条件判断中的分配: 将泛型参数用 [] 括起来, 这样传入的参数将作为一个整体
type M<T> = [T] extends ['x'] ? string : number;
type A6 = M<'x' | 'y'>; // number
type A7 = M<never>; // string
/**
* 索引类型
* 索引类型的查询操作符: keyof keyof T 表示类型T的所有公共属性的字面量的联合类型示
* 索引访问操作符:T[K] 表示对象T的属性K所代表的类型
*/
interface Obj_1 {
name: string;
sex: boolean;
}
// 定义变量key,类型为keyof Obj
let key: keyof Obj_1;
let keys: Obj_1['sex'];
/**
* 映射类型
* { [ P in K ]: T }
* { [ P in K ]?: T }
* { [ P in K ]-: T }
* { readonly [ P in K ]: T }
* { readonly [ P in K ]?: T }
* { -readonly [ P in K ]?: T }
* [P in K] 注: P 为变量 类似于 for in中定义在in前方的i K 是需要遍历的数组或对象
* [P in K] 遍历目标类型的公开属性名; 类似 for in
* is 判断变量是否属于某个类型可以理解为 !!
* infer: 条件类型中的类型推断 需要和三目运算或extends同时使用
* 映射类型: 将原有的对象类型映射成新的对象类型 可以理解为对key和value 的操作
*
* 可选属性: Partial<T> // 将必选属性变成可选属性
* * 源码: type Partial<T> = { [P in keyof T]?: T[P] }
* 只读属性:Readonly<T> // 将非只读属性转换成只读属性
* * 源码:type Readonly<T> { readonly [P in keyof T]: T[P] }
* 动态构造:Record<K extends keyof any, T> // 以typeof格式快速创建类型
* * 源码:type Record<K extends keyof any, T> = { [P in K]: T }
* 选择/挑选属性: Pick<类型,需要被取出的属性> // 从定义的属性中取出一组属性返回
* * 源码:type Pick<T, K extends keyof T> = { [P in K]: T[P] }
* 必选属性: Required<T>
* * 源码:type Required<T> = { [P in keyof T]-?: T[P]; }
* 排除属性: Exclude<T, U>
* * 源码:type Exclude<T, U> = T extends U ? never : T
* 提取属性: Extract<T, U>
* * 源码:type Extract<T, U> = T extends U ? T : never
* 忽略属性:Omit<T, K>
* * 源码:type Omit<T, K extends string | number | symbol> = { [P in Exclude<keyof T, K>]: T[P]; }
* 排除null和undefined:NonNullable<T>
* * 源码:type NonNullable<T> = T extends null | undefined ? never : T
* 获取函数参数返回类型:Parameters<T>
* * 源码:type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
* 获取函数返回类型:ReturnType<T>
* * 源码:type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
*/
type A8<T> = {
[P in keyof T]?: T[P]
}
interface Obj_2 { name: string }
type A9 = A8<Obj_2>; // type = { name?: string | undefined}
type A10 = { // type A10 = { x ?: number | undefied; ... }
[P in 'x' |'y']?: number | undefined;
}
type A11 = {
a?: string;
b?: number;
c?: boolean;
}
// 可以简写为 type A11Key = keyof A11;
type A11Key = 'a' | 'b' | 'c';
type A12 = { [K in A11Key]: A11[K] }; // A12 = { a: string; ... }
// A11 -> A12 步骤可以简化为
type A13 = { [K in keyof A11]:A11[K] }; // 与 A12 结果一样
// 也可以写成这样
type A14<P> = { [K in keyof P]: P[K] }; //
type A15 = A14<A11>; // 与 A12 结果一样
/**
* 泛型接口
* interface <泛型变量> {}
*/
interface generic_interface_1<T> {
name: T;
sex: T;
age: number,
}
const generic_var_1:generic_interface_1<string> = {
name: "wzy",
// 报错 不能将 布尔类型分配给 string 这是因为 上面传递的类型是 string类型
// 如果需要使用 布尔类型可以传递一个联合类型 或者修改接口
// sex: false,
sex: "女",
age: 16,
}
const generic_var_2:generic_interface_1<string | boolean> = {
name: "wzy",
sex: false, // 不报错了
age: 18
}
// 定义函数的形式
interface generic_interface_2 {
<T>(length:number, value: T): Array<T>;
}
const generic_var_3: generic_interface_2 = function<T>(length:number, value: T):Array<T>{
let arr: T[] = [value];
return arr;
}
// 将T提前到接口
interface generic_interface_3<T> {
(length:number, value: T): Array<T>;
}
const generic_var_4: generic_interface_3<string> = function <T>(length:number, value: T): Array<T>{
let arr: T[] = [value];
return arr;
}
console.log(generic_var_4(12, "24"));
/**
* 泛型类
* class 类名 <泛型变量> {}
* new 类名<类型>();
*/
class generic_class_1<T> {
public list:T[] = [];
add(value: T): void {
}
minNumber(value: T): T {
return value;
}
}
const generic_var_5 = new generic_class_1<number>()
// 意思是 类型T 必须满足 any
class generic_class_2 <T extends Record<string, any>>{
private _studentsArray: Array<T>= [];
delete<K extends keyof T>(key: K, value: string): void {
for(let item in this._studentsArray){
if (this._studentsArray[item]?.[key] == value) {
this._studentsArray.splice(Number(item), 1);
}
}
}
}
type x25 = {
name: string;
sex: number;
}
type x05 = Record<keyof x25, number>
/**
* 泛型约束
* 在函数内使用 泛型类型的变量的时候因为不知道 变量具体的类型 所以无法使用变量的方法和属性
* 泛型约束: <泛型变量 extends 需要被满足的约束>
* 多个参数之间的约束: <泛型变量1, 泛型变量2 extends 泛型变量1 >
* keyof关键字:能够获取一个 interface 或对象 的全部 key 也可以获取变量的类型
*/
// 约束
interface i1 {
name: string;
sex: boolean;
}
type ob = {name: "wzy"}
function funs<T, U extends keyof T>(param: T){
console.log(param);
}
funs<i1, `name`>({name: "wzy", sex: false})
type xxxx = keyof {name: string, value: string, key: string | number};
// 限制函数参数和返回值类型
// 泛型约束:在函数内部使用类型为泛型变量的变量的时候,因为泛型的原因不确定变量是什么类型,所以不能随意操作属性和方法
function generic_fun_1<T>(value: T): T{
// console.log(value.length); // 报错 类型“T”上不存在属性“length”。
return value;
}
console.log(generic_fun_1<string>("string"));
function generic_fun_1s<T extends string>(value: T): T{
console.log(value.length); // 限制没有报错了
return value;
}
// 限制构造函数参数类型以及成员变量、方法参数的类型
class generic_class_3 <T>{
name: T;
constructor(name: T){
this.name = name;
}
action(say: T): T {
return say;
}
}
const generic_var_6 = new generic_class_3<string>("限制");
console.log(generic_var_6?.action("0556"));
// 定义多个泛型变量
function generic_fun_2<T, U>(tuple: [T, U]): [U, T]{
return [tuple[1], tuple[0]];
}
console.log(generic_fun_2<string, number>(["xy", 11]));
// 泛型变量的默认值
function generic_fun_3<T = string>(){}
generic_fun_3()
/**
* 预定义的有条件类型
* Exclude<T, U> -- 从T中剔除可以赋值给U的类型。
* Extract<T, U> -- 提取T中可以赋值给U的类型。
* NonNullable<T> -- 从T中剔除null和undefined。
* ReturnType<T> -- 获取函数返回值类型。
* InstanceType<T> -- 获取构造函数类型的实例类型。
*/