ts_05_泛型

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> -- 获取构造函数类型的实例类型。
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值