泛型重点学习

1.泛型是什么?

泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数和函数返回值。‘

// 举个例子
// 定义一个 demo 函数,接受一个参数并且返回
function demo(value){
    return value;
}

console.log(demo(1));  //1
console.log(demo('kjh'));  //'kjh'

// 接着我们对 demo 函数做适当的调整,以支持 TypeScript 的 Number 类型的参数:
function demoWithTS(value:number):number{
    return value;
}

console.log(demoWithTS(100)); //100
// console.log(demoWithTS('kjh'));  //type error


// 但是当前的函数无法拓展,即当我们想要传入一个字符串,布尔值的时候不能满足。
// 解决方法1: 采用any  否定:丢弃了 ts 类型检查的好处
// 解决方法2: 采用泛型

function demoWithGeneric<T>(value: T): T {
    return value;
}

console.log(demoWithGeneric(1));  //1
console.log(demoWithGeneric<string>('kjh'));  //'kjh'

2.泛型接口

// 泛型接口
// 我们新的函数增加了一个类型变量 U,我们如果想要返回两种类型的对象该怎么办呢?

// 采用元组的方法
function newDemo01 <T,U>(name:T, age:U):[T,U] {
    return [name,age];
}

console.log(newDemo01<string,number>('kjh',22));  // ['kjh',22]



// 我们也可以返回一个新的对象类型
function newDemo02<T,U>(name:T,age:U):{name:T,age:U}{
    return {
        name,
        age
    }
}

console.log(newDemo02<string,number>('kangjiahao',100));
//{ name: 'kangjiahao', age: 100 }


// 将这个对象类型提取出来
interface DemoType<T,U>{
    name:T,
    age:U
}

function newDemo03<T,U>(name:T,age:U):DemoType<T,U>{
    return {
        name,
        age
    }
}

console.log(newDemo03<string,number>('kangjiahao',200));
//{ name: 'kangjiahao', age: 100 }

3.泛型类

// 定义一个队列类
class Queue {
    public queueItems;
    constructor(){
        this.queueItems = [];
    }

    enqueue(value){
        this.queueItems.push(value);
        return true;
    }

    dequeue(){
        const result = this.queueItems.shift();
        return result;
    }

    size(){
        return this.queueItems.length;
    }
}

const queue = new Queue();


// 定义泛型类
interface QueueType<T> {
    queueItems:T[],
    enqueue(value:T):boolean,
    dequeue():T,
    size():number
}


class QueueWithTs<T> implements QueueType<T>{
    public queueItems: T[];
    enqueue(value:T){
        this.queueItems.push(value);
        return true;
    }

    dequeue(){
        const result = this.queueItems.shift();
        return result;
    }

    size(){
        return this.queueItems.length;
    }
}

4.泛型约束

4.1 type 和 interface 的区别和联系

// 联系1: 都可以描述一个对象
interface User {
    name:string;
    age:number;
}

type Person = {
    name:string;
    age:number;
}



// 联系2: 都可以进行拓展
// interface 拓展
interface Sex extends User{
    sex:string;
}

interface Home extends Person {
    home:string;
}

// type 拓展
type Party = Person & {party:string};

type Car = User & {car:string};


// 区别1: type 可以但是 interface 不可以的
// type 可以声明基本类型别名,联合类型,元组等类型
type Name = string;

type Kinds = number | string;

// type 可以使用 typeof 获取实例的理性之后进行赋值

let div = document.createElement('div');
type B = typeof div;

// 区别2: interface 能够声明合并
interface Animal {
    eat():void;
    drink():void;
}

interface Animal {
    run():void;
}

const dog : Animal = {
    // eat, drink, run .....
}

4.2 确保属性存在

// 有时候我们在处理字符串或者数组的时候,我们会假设length属性是可用的。

function demo<T>(arg:T):T {
    // console.log(arg.length);   // error
    return arg;
}

// 编译器不会知道T确实韩式含有 length 属性,我们需要让类型变量 extends 一个含有我们所需要属性的接口

interface ProviderLength {
    length:number;
}

function demo2<T extends ProviderLength>(arg:T):T{
    console.log(arg.length)
    return arg;
}


//这样编译器就不会报错了,当然我们传入没有length的数据类型也会包error

4.3 keyof

// keyof 操作符是在 TypeScript 2.1 版本引入的,该操作符可以用于获取某种类型的所有键,其返回类型是联合类型

interface Person {
    name:string;
    age:number;
    location:string;
}


type K1 = keyof Person; // "name" | "age" | "location"



4.4 检查对象上的键是否存在


// 举个例子,我们想要返回一个对象身上的某个属性
function getProperty<T,K extends keyof T>(obj:T, key:K): T[K]{
    return obj[key];
}


getProperty({name:'ts'},'name');   // allow

5 泛型条件类型

条件类型会以一个条件表达式进行类型关系检测,从而在两种类型中选择其一

interface Father {
    blood:'O',
}

interface Mather {
    blood2:'X'
}

type Son<T> = T extends Father ? Father :Mather; 

type boy = Son<{}>; //Mather
type girl = Son<{blood:'O'}>; // Father

结合泛型推断infer使用

// infer 的中文是“推断”的意思,一般是搭配上面的泛型条件语句使用的,所谓推断,就是你不用预先指定在泛型列表中,在运行时会自动判断,不过你得先预定义好整体的结构。

type Foo<T> = T extends {t: infer Test} ? Test: string;

// 首选看 extends 后面的内容,{t: infer Test}可以看成是一个包含t属性的类型定义,这个t属性的 value 类型通过infer进行推断后会赋值给Test类型,
// 如果泛型实际参数符合{t: infer Test}的定义那么返回的就是Test类型,否则默认给缺省的string类型。


// 举个例子
type MyNumber = Foo<number>;  // string

type YourNumber = Foo<{t:number}>; // number

6.泛型工具类型

6.1 Partial

Partial 的作用就是将某个类型里的属性全部变为可选项 ?。

// type Partial<T> = {
//     [P in keyof T]?: T[p];
// }

举例:

interface StudentType {
    name:string;
    age:number;
    home:string;
}

const xiaoming:Partial<StudentType> = {
    name:'string',
    //......
}
6.2 Record

Record<K extends keyof any, T> 的作用是将 K 中所有的属性的值转化为 T 类型。

type Record<K extends keyof any, T> = {
    [P in K]: T;
};

举例:

interface PageInfo {
    info:string;
}

type Page = "home" | "about";

const newPage: Record<Page,PageInfo> = {
    home:{info:"home"},
    about:{info:"about"}
}



// 实际应用
// 我现在需要一个对象,有ABC三个属性,且属性的值必须都是数字。
type Keys = 'A' | 'B' | 'C';

const obj : Record<Keys,number> = {
    A:1,
    B:2,
    C:3
}
6.3 Pick

Pick<T, K extends keyof T> 的作用是将某个类型中的子属性挑出来,变成包含这个类型部分属性的子类型。

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

举例:

interface Animal {
    dog:string;
    cat:string;
    bird:string;
    fish:string;
}

const FiledAnimal : Pick<Animal,"dog" | "cat"> = {
    dog:"xiaohei",
    cat:"xiaohua"
}
6.4 Exclude<T,U>

此工具是在 T 类型中,去除 T 类型和 U 类型的交集,返回剩余的部分。

type Exclude<T, U> = T extends U ? never : T

举例:

type Test1 = Exclude<"a" | "b" | "c", "a">;  // "b" | "c"

6.5 ReturnType

ReturnType 的作用是用于获取函数 T 的返回类型。

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

举例:

type Test2 = ReturnType<() => string>;  // string
6.6 Required

此工具可以将类型 T 中所有的属性变为必选项。

type Required<T> = {
  [P in keyof T]-?: T[P]
}

举例:

interface StudentType {
    name:string;
    age?:number;
    home?:string;
}

const xiaoming:Required<StudentType> = {
    name:'string',
    age:18,
    home:'xian'
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值