ts 学习笔记 - 泛型

泛型

泛型(Generics)是指在定义函数、接口或者类的时候, 不预先指定其类型,而是在使用是手动指定其类型的一种特性。

举个栗子

我们需要创建一个函数, 这个函数会返回任何它传入的值。

正常代码如下:

function identity(arg: any): any {
  return arg
}

identity(3) // 3

这代代码编译不会出错,但是存在一个显而易见的缺陷, 就是没有办法约束输出的类型与输入的类型保持一致。

这时,我们可以使用泛型来解决这个问题;

function identity<T>(arg: T): T {
  return arg
}

identity(3) // 3

上例中,我们在函数名后面加了 <T>, 其中的 T 表示任意输入的类型, 后面的 T 即表示输出的类型,且与输入保持一致。

当然我们也可以在调用时手动指定输入与输出的类型, 如上述函数指定 string 类型:

identity<number>(3) // 3

泛型约束

在泛型函数内部使用类型变量时, 由于事先并不知道它是那种类型, 所以不能随意操作它的属性和方法:

function loggingIdentity<T>(arg: T): T {
  console.log(arg.length)   // err 
  return arg
}

上述函数中 类型 T 上不一定存在 length 属性, 所以编译的时候就报错了。

这时,我们可以的对泛型进行约束,对这个函数传入的值约束必须包含 length 的属性, 这就是泛型约束:

interface lengthwise {
  length: number
}

function loggingIdentity<T extends lengthwise>(arg: T): T {
  console.log(arg.length)   // err 
  return arg
}

loggingIdentity({a: 1, length: 1})  // 1
loggingIdentity('str') // 3
loggingIdentity(6) // err  传入是参数中未能包含 length 属性

这样我们就可以通过泛型约束的方法对函数传入的参数进行约束限制。

多个参数时也可以在泛型约束中使用类型参数

如你声明了一个类型参数, 它被另一类型参数所约束。现在想要用属性名从对象里湖区这个属性。并且还需确保这个属性存在于这个对象上, 因此需要咋这两个类型之间使用约束,

简单举例来说: 定义一个函数, 接受两个参数 第一个是个对象 obj,第二个个参数是第一参数 key 是对象里面的键名, 需要输入 obj[key]

function getProperty<T, K extends keyof T>(obj: T, key: K) {
  return obj[key]
}

let obj = { a: 1, b: 2, c: 3 }

getProperty(obj, 'a') // success
getProperty(obj, 'm') // err obj 中不存在 m 这个参数

泛型接口

interface CreateArrayFunc {
  <T>(length: number, value: T): Array<T>
}

let createArr: CreateArrayFunc
createArr = function<T>(length: number, value: T): Array<T> {
  let result = T[]: []
  for(let i = 0; i < length; i++) {
        result[i] = value
  }
  return result
}
createArray(3, 'x'); // ['x', 'x', 'x']

进一步的, 还可以把泛型参数提前到接口名上:

interface CreateArrayFunc<T> {
  (length: number, value: T): Array<T>
}
  
let createArr: CreateArrayFunc<any>
    
createArr = function<T>(length: number, value: T): Array<T> {
  let result = T[]: []
  for(let i = 0; i < length; i++) {
        result[i] = value
  }
  return result
}
createArray(3, 'x'); // ['x', 'x', 'x']

注意: 此时使用泛型接口时, 需要定义泛型的类型

泛型类

与泛型接口类型,泛型也可以定义在类的类型定义中:

class GenericNumber<T> {
  zeroValue: T
  add: (x: T, y: T) => T
}
let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroNumber = 0
myGenericNumber.add = function(x, y) {
  return x + y
}

注意: 类有两部分: 静态部分和实例部分。泛型类值的是实例部分的类型,所以类的静态属性不能使用这个泛型类型

泛型参数的默认类型

在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。

function createArr<T = string>(length: number, value: T): Array<T> {
  let result: T[] = []
  for( let i = 0; i < lenght; i++ ) {
    result[i] = value
  }
  return result
}

转载于:https://www.cnblogs.com/vant850/p/11413623.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值