likes
comments
collection
share

TS之泛型

作者站长头像
站长
· 阅读数 4

一、泛型 

泛型: 是指附属于类型、类、接口、类型别名之上的类型。

  • 书写某个函数时,会丢失一些类型信息(多个位置的类型应该保持一致或有关联的信息)。
  • 泛型相当于是一个类型变量,在定义时,无法预先知道具体的类型,可以用该变量来代替,只有到调用时,才能确定它的类型。
  • 很多时候, TS 会智能的根据传递的参数,推导出泛型的具体类型。 
  • 如果无法完成推导,并且又没有传递具体的类型,默认为空对象
  • 泛型可以设置默认值。 

1.在函数中使用泛型

在函数名之后写上 <泛型名称> :

为函数指定一个泛型,名称为 T ,调用函数时传递一个 number 类型,则 T 为 number 类型,可以作为函数参数、函数返回值、和函数里面数值类型使用。下方示例中,为 T 指定了默认类型为 number 。

function take<T = number>(arr:T[],n:number): T[] { 
  if (n >= arr.length) { 
    return arr;
  }
  const newArr: T[] = []
  for (let i = 0; i < n; i++) { 
    newArr.push(arr[i])
  }
  return newArr
}
const newArr = take<number>([1, 2, 3, 4, 5], 2)
console.log(newArr); // [ 1, 2 ]

2.在类型别名、接口和类中使用泛型

类型别名直接在名称后写上 <泛型名称> :

type callback<T> = (n: T, i: number) => boolean
function filter<T>(arr: T[], callback: callback<T>): T[] {
  const newArr: T[] = []
  arr.forEach((n, i) => { 
    if (callback(n, i)) { 
      newArr.push(n)
    }
  })
  return newArr
}
const arr = [3, 4, 5]
console.log(filter<number>(arr, n => n % 2 !== 0)); // [ 3, 5 ]

接口直接在名称后写上 <泛型名称> :

interface callback<T> {
  (n: T, i: number): boolean
}
function filter<T>(arr: T[], callback: callback<T>): T[] {
  const newArr: T[] = []
  arr.forEach((n, i) => { 
    if (callback(n, i)) { 
      newArr.push(n)
    }
  })
  return newArr
}
const arr = [3, 4, 5]
console.log(filter<number>(arr, n=> n % 2 !== 0)); // [ 3, 5 ]

 直接在名称后写上 <泛型名称> :

ArrayHelper.ts :

export class ArrayHelper<T> { 
  constructor(private arr: T[]) { }
 
  take(n:number): T[] { 
    if (n >= this.arr.length) { 
      return this.arr;
    }
    const newArr: T[] = []
    for (let i = 0; i < n; i++) { 
      newArr.push(this.arr[i])
    }
    return newArr
  }
 
  shuffle() { 
    for (let i = 0; i < this.arr.length; i++) {
      const targetIndex = this.getRandom(0, this.arr.length)
      const temp = this.arr[i]
      this.arr[i] = this.arr[targetIndex]
      this.arr[targetIndex] = temp
    }
  }
 
  private getRandom(min: number, max: number) { 
    const dec = max - min
    return Math.floor(Math.random() * dec + max)
  }
}

index.ts :

TS之泛型

由于 TS 自带的类型推导,所以 <泛型名称> 有时可以省略。

二、泛型约束 

泛型约束: 用于限制泛型的取值。

在下方代码中定义一个接口,里面有一个属性 name 为字符串类型,函数中使用继承了该接口属性的泛型作为函数的参数和返回值。 泛型约束满足鸭子辨型法。

interface hasNameProperty {
  name: string
}
const person = {
  name: "rata li",
  age: 18,
  gender:"男"
}
/**
 * 将某个对象的name属性的每个单词的首字母转换为大写,然后返回该对象
 */
function nameToUpperCase<T extends hasNameProperty>(obj:T): T {
  obj.name = obj.name
    .split(" ")
    .map(i => i[0].toUpperCase() + i.substring(1))
    .join(" ")
  return obj
}
const newPerson = nameToUpperCase(person)
console.log(newO.name) // Rata Li

 此时,参数中必须包含 name 属性,如果去掉对象 person 中的 name 属性,则会报错:

TS之泛型

三、多泛型 

多泛型:写一些函数或者类时,依赖多个类型的时候需要使用多泛型。

/**
 * 将两个数组进行混合,[1,3,4] ["a","b","c"] => [1,"a",2,"b",3,"c"]
 */
function mixinArray<T, K>(arr1: T[], arr2: K[]): (T | K)[] {
  if (arr1.length !== arr2.length) { 
    throw new Error("两个数组长度不等")
  }
  let newArr: (T | K)[] = []
  for (let i = 0; i < arr1.length; i++) { 
    newArr.push(arr1[i]);
    newArr.push(arr2[i]);
  }
  return newArr
}
const arr = mixinArray([1, 2, 3], ["a", "b", "c"])
console.log(arr);
转载自:https://juejin.cn/post/7348715168571916340
评论
请登录