TypeScript泛型(generic)

2019-11-21  本文已影响0人  不思量q
/**
 * generic泛型,给予了开发者创造灵活、可重用代码的能力
 * 场景1,假设有个函数A,接受number类型的参数,并返回number类型的值
 * 那如果同样的函数B,参数和返回值类型要改变成string,那非得写两个函数么,或者写成any类型?
 * 也就是说在静态编写的时候并不确定传入的参数类型,只有运行时传入参数后才可确定
 * 这里可以看做需要一个变量,变量代表了传入的类型,然后再返回这个变量,它为一种特殊变量,只用于表示类型而不表示值,即为泛型
 */
function getType(para: string): string {
  return para
}

function returnItem<T>(para: T): T {
  return para
}
// 编译成JS文件后这俩函数是一样的

// 多个参数类型
function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]]
}
console.log(swap([2, '2oops'])) // ['2oops', 2]

// 假设函数接收一个数组,要求打印数组长度,并返回数组
function getLength<T>(arg: Array<T>) {

  console.log((arg as Array<any>).length)
  return arg
}
getLength([1,2,3])

// 泛型接口
interface ReturnItemFn<T> {
  (para: T): T
}
const Fun1: ReturnItemFn<string> = params => params + '2oops'
console.log(Fun1('hello '))

// 泛型类
class Stack {
  private arr: number[] = []

  public push(item: number) {
    this.arr.push(item)
  }

  public pop() {
    this.arr.pop()
  }
}

class GenericStack<T> { // 泛型在类中使用
  private arr: T[] = []

  public push(item: T) { // 泛型在类的成员函数中使用
    this.arr.push(item)
  }

  public pop() {
    this.arr.pop()
  }
}

// 泛型约束 <T extends types>
type types = number | string

class TypeStack<T extends types> {
  private arr: T[] = []

  public push(item: T) {
    this.arr.push(item)
  }

  public pop() {
    this.arr.pop()
  }
}

const stack1 = new TypeStack<number>()
// const stack2 = new TypeStack<boolean>()

// 泛型约束和索引类型
// 假设设计一个函数接收一个对象和对象的属性作为参数,通过这两个参数返回这两个值
// 直接JS实现可能会写成下面这样,但这是不严谨的
// function getValue(obj, key) {
//   return obj[key]
// }
// 然后用TS写成这样?obj为空的场景?
// function getValue(obj: object, key: string) {
//   return obj[key] // error
// }

// 正确写法
function getValue2<T extends object, U extends keyof T>(obj: T, key: U) {
  console.log(obj[key])
  return obj[key]
}

const obj1 = {
  name: '2oops',
  age: 20
}
getValue2(obj1, "name") // '2oops'

// 使用多重类型进行泛型约束
// 假设泛型被需要被以下两个接口约束
interface first {
  doSomething(): number
}
interface second {
  doSomethingElse(): string
}

// 或许我们会这样使用
// class interfaceGeneric<T extends first, second> {
//   private genericProperty: T

//   useT() {
//     this.genericProperty.doSomething()
//     // this.genericProperty.doSomethingElse() //报错不存在该泛型
//   }
// }

// 这时可以将俩接口作为超接口
interface ChildInterface extends first, second {

}
class interfaceGeneric<T extends ChildInterface> {
  private genericProperty: T
  // 如果直接这样写会报错,这时需要在tsfonfig.json设置下`"strictPropertyInitialization": false`
  // 报错参考https://stackoverflow.com/questions/49699067/property-has-no-initializer-and-is-not-definitely-assigned-in-the-construc

  useT() {
    this.genericProperty.doSomething()
    this.genericProperty.doSomethingElse()
  }
}

// 泛型和new
// 声明一个泛型其拥有构造函数
function factory<T>(type: {new(): T}): T {
  return new type()
}
上一篇下一篇

猜你喜欢

热点阅读