泛型

 泛型:组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,用户就可以以自己的数据类型来使用组件。更加灵活

泛型接口

  //泛型接口的第一种定义方式 当这个接口去限制函数,推荐使用这个
  interface IPrint {
    <T>(value: T): T
  }
  const print: IPrint = value => value

  print<string>('abc') //在函数调用时候显示传入T类型
  print('bbb') //这是简写 这样更普遍 利用了类型推断 编译器自动根据所传参数类型'abc'确定T的类型

  
  // 泛型接口的第二种定义方式  当这个接口去实现类implement 推荐使用这种定义方式。
  interface IIdentity1<T> {
    (arg: T): T
  }
  //这样 我就必须在函数定义的时候传入T类型,但是我不知道在函数定义时候传入什么类型。 而不是调用时候传入T类型,这种不好 
  const print1: IIdentity1<any> = value => value //这里IIdentity1必须要求我传入T的类型。传入具体的类型不太好。因为到时候限制我的调用,只能传入具体的类型,所以不得已传入any,传入any后面调用是没有提示的
  const r=print1(100) //r在这个时候是不明确它的类型的,编辑器是没有任何提示
  
  const print2: IIdentity1<string> = value => value 
  const r2=print2('abc') //r2明确知道是string类型。但是也只能传入string类型数据,失去了泛型的意义
  // print2(100)Error  Argument of type 'number' is not assignable to parameter of type 'string'.

例子2

 // 定义泛型接口
  interface IAddFunc {
    <T>(value1: T, value2: T): string | number
  }

  const add: IAddFunc = (value1, value2) => {
    // 直接 return value1+value2 是会报错的 Operator '+' cannot be applied to types 'T' and 'T'.
    if (typeof value1 === 'string' && typeof value2 === 'string') return value1 + value2
    if (typeof value1 === 'number' && typeof value2 === 'number') return value1 + value2
  }
  console.log(add('aaa', 'bbb'))
  console.log(add(10, 20))

更简洁的写法


interface IAddFunc {
    <T>(value1: T, value2: T): T
  }
  const add: IAddFunc = <IAddFunc>(value1, value2) => { //<IAddFunc>是类型断言 尝试用as但是报错了why
    return value1 + value2
  }
  console.log(add(1, 2))
  console.log(add('a', 'b'))
  // add(1, 'a') //Error
 

泛型类

class ClassName<T> //T可以是基本数据类型:number|string; 也可以是自定义类类型。其他类型应该也可以传进来当作T的类型

// 泛型类
  class MinClass<T>{
    list: Array<T> = []
    push(value: T): void {
      this.list.push(value)
    }
    getMin(): T {
      let minIndex = 0
      for (let i: number = 1; i < this.list.length; i++) {
        if (this.list[minIndex] > this.list[i]) minIndex = i //找出最小值索引
      }
      return this.list[minIndex]
    }

  }
  // 数字类型
  const minNumber = new MinClass<number>()
  minNumber.push(1)
  minNumber.push(30)
  minNumber.push(5)
  minNumber.push(-7)
  minNumber.push(0)
  minNumber.push(100)
  const minNum = minNumber.getMin() //minNum可以确定是number类型 无需显示表示,如果要表示就是number类型

//字符串类型 const minString = new MinClass<string>() minString.push('f') minString.push('d') minString.push('4') minString.push('ebe') minString.push('few') minString.push('wewr') const minStr = minString.getMin() ///minStr可以确定是string类型 无需显示表示,如果要表示就是string
class User {
    name: string;
    age: number;
    constructor(name: string, age: number) {
      this.name = name
      this.age = age
    }
  }
  class Article {
    title: string;
    time: Date
    desc?: string;
    constructor(title: string, desc?: string, time: Date = new Date) {
      this.title = title
      this.time = time
      this.desc = desc
    }
  }



  class SqlDb<T>{ //T可以是自定义类类型 我想甚至接口都可以传进来
    list: Array<T> = [] //定义一个空泛型对象
    add(item: T): void {
      this.list.push(item)
    }
  }


  const u1 = new User('zs', 10)
  const u2 = new User('lisi', 12)
  const article = new Article('三国演义', '曹操-孙权-刘备')
  const article1 = new Article('红楼梦', '贾宝玉-林黛玉-薛宝钗')
  const userDB = new SqlDb<User>() //看这里 传入自定义类型User
  
  userDB.add(u1)
  userDB.add(u2)
  const articleDB = new SqlDb<Article>() //看这里 传入自定义类型Article
  articleDB.add(article)
  articleDB.add(article1)

泛型约束

例子1

interface ILength {
    length: number //限制泛型必须有length 属性
  }
  interface ILoggingIdentity {
    <T extends ILength>(value: T): T // <T extends ILength> 表示T类型必须有length属性
  }
  const loggingIdentity: ILoggingIdentity = value => {
    console.log(value.length);//我输出length属性 肯定是希望我传入的变量是有length属性的
    return value
  }
  loggingIdentity('abc')
  loggingIdentity({ name: 'zs', age: 10, length: 10 })

泛型类型别名 type定义

 // 接口和type interface定义一个实实在在的接口,接口是一个真正的类型。type一般是定义别名,大白话:type 就是给一个类型起一个新名字。不会产生一个新的类型
  //类型别名type不能用extends implements扩展接口, interface可以
  // 泛型类型别名 type定义
  type CartType<T> = { list: Array<T> } | Array<T> //| 或者意思
  const cart1:CartType<string>={list:['1','2']}
  const cart2:CartType<number>=[1,2,3]

综合案例

里面有自定义类接口约束

/*
  定义一个操作数据库的库同时支持mysql mssql mongDB(泛化),同时都有add update delete get方法(接口实现类)

  //注意描述:约束统一的规范(接口);代码的重用(泛型)
  */
  interface DBI<T> { //接口去定义方法 然后用类去实现这个接口implement
    add: (item: T) => boolean
    update: (item: T, id: number) => boolean
    deleteById: (id: number) => boolean
    getById: (id: number) => T
  }
  interface IId { //接口约束T必须有Id属性
    id: number
  }
  // 定义一个操作mysql数据库的类 注意:要实现泛型接口,这个类也应该是一个泛型类
  // 新的知识点 自定义类约束 <T extends IId> 约束T自定义类实例有id属性
  class MySqlDb<T extends IId> implements DBI<T>{
    list: Array<T> = []
    add(item: T) {
      this.list.push(item)
      return true
    }
    update(item: T, id: number) { return true }
    deleteById(id: number) {
      this.list = this.list.filter(item => item.id !== id)

      return true
    }
    getById(id: number): T {
      return this.list.find(item => item.id === id)
    }

  }
  class User {
    id: number
    user: string;
    password: string
    constructor(id: number, user: string, password: string) {
      this.user = user
      this.password = password
      this.id = id
    }
  }
  const u1 = new User(1000, 'zs', '123456')
  const u2 = new User(1001, 'lisi', '123456')
  const mySqlDb = new MySqlDb<User>()
  mySqlDb.add(u1)
  mySqlDb.add(u2)
  console.log('8888888888888888');

  console.log(mySqlDb.getById(1001))
  mySqlDb.deleteById(1001)
  console.log(mySqlDb.list);


  //定义一个操作mssql数据库的类
  class MsSqlDb<T> implements DBI<T>{
    add: (item: T) => boolean;
    update: (item: T, id: number) => boolean;
    deleteById: (id: number) => boolean;
    getById: (id: number) => T;
  }
  //定义一个操作mongDB数据库的类
  class MonDb<T> implements DBI<T>{
    add: (item: T) => boolean;
    update: (item: T, id: number) => boolean;
    deleteById: (id: number) => boolean;
    getById: (id: number) => T;

  }
原文地址:https://www.cnblogs.com/xiaoliziaaa/p/14930373.html