TypeScript 第五章:泛型 Generics

泛型指使用时才定义类型,即类型可以像参数一样定义,主要解决类、接口、函数的复用性,让它们可以处理多种类型。


基本使用

下面示例返回值类型是 any,这不是我们想要的,因为我们想要具体返回类型

function dump(arg: any) {
    
    
    return arg;
}

let hj = dump('hj') // 类型为 any
let hk = dump(true) // 类型为 any

使用了泛型定义后,返回值即为明确的类型

function dump<T>(arg: T): T {
    
    
    return arg;
}

let hj = dump<string>('hj') // 类型为 string

如果调用时不指定类型系统也会自动推断类型

...
let hk = dump(true) // 类型为 boolean
...

类型继承

  • 下面的代码是不严谨的,我们不需要处理数字,因为数字没有 length 属性,同时我们希望返回类型不是 any
const getLength = (args: any) => {
    
    
    return args.length
}

console.log(getLength('hj')); // 2
console.log(getLength([1, 2, 3])); // 3
console.log(getLength(123)); // undefined

  • 泛型是不确定的类型,所以下面读取 length 属性将报错
const getLength = <T>(args: T): number => {
    
    
    return args.length // 类型“T”上不存在属性“length”
}

我们可以通过继承来解决这个问题

const getLength = <T extends string>(args: T): number => {
    
    
    return args.length
}

  • 上例只能处理字符串,不能处理数组等包含 length 的数据,我们可以通过继承 extends 继承,让泛型定义包含 length 属性
const getLength = <T extends {
    
     length: number }>(args: T): number => {
    
    
    return args.length
}

// 或使用 interface 或 type

type LengthType = {
    
     length: number }
function getLengthAttribute<T extends LengthType>(args: T): number {
    
    
    return args.length;
}
  • 如果你的类型只是字符串或数组,也可以使用联合类型
const getLength = <T extends string | any[]>(args: T): number => {
    
    
    return args.length
}

下面我们来掌握在类中使用泛型的方法

使用泛型复用类

下面是对数值与字符串类型的集合进行管理,因为业务是一样的,所以下面的实现是重复的

class CollectionNumber {
    
    
    data: number[] = []
    public push(...items: number[]) {
    
    
        this.data.push(...items)
    }
    public shift() {
    
    
        return this.data.shift()
    }
}

class CollectionString {
    
    
    data: string[] = []
    public push(...items: string[]) {
    
    
        this.data.push(...items)
    }
    public shift() {
    
    
        return this.data.shift()
    }
}

const numberCollection = new CollectionNumber()
numberCollection.push(1)
const stringCollection = new CollectionString()
stringCollection.push('hj', 'hk')

console.log(stringCollection.shift());

上例使用泛型来控制就好多了

class Collection<T> {
    
    
    data: T[] = []
    public push(...items: T[]) {
    
    
        this.data.push(...items)
    }
    public shift() {
    
    
        return this.data.shift()
    }
}

const collections = new Collection<number>()
collections.push(1)

type User = {
    
     name: string, age: number }
const hj: User = {
    
     name: "hj", age: 18 }
const userCollection = new Collection<User>()

userCollection.push(hj)
console.log(userCollection.shift());

接口结合泛型

下面的代码是不稳定的,我们的意图是传递用户数据,但没有类型约束情况下,可以传递任何类型

class User {
    
    
    constructor(protected _user) {
    
     }
    public get() {
    
    
        return this._user
    }
}

const instance = new User({
    
     name: 'hj' })
console.log(instance.get());

对类使用泛型处理后,可以保证传递与返回值的类型,并具有良好的代码提示

class User<T> {
    
    
    constructor(private _user: T) {
    
    
        this._user = _user
    }
    public get user(): T {
    
    
        return this._user
    }
}

interface UserInterface {
    
    
    name: string
    age: number
}
const hj = new User<UserInterface>({
    
     name: 'hj', age: 19 })
console.log(hj.user); // { name: 'hj', age: 19 }

接口

下面对接口的类型使用泛型定义,比如 isLock 可以为 numberboolean,并对文章的评论内容进行定义。

这样处理代码会有严格类型约束,并有良好的代码提示

interface ArticleInterface<T, B> {
    
    
    title: string
    canComment: B
    comments: T[]
}

type CommentType = {
    
    
    comment: string
}

const hj: ArticleInterface<CommentType, boolean> = {
    
    
    title: 'generics',
    canComment: true,
    comments: [
        {
    
     comment: '真棒' }
    ]
}
console.log(hj);

值类型

下面解构得到的变量类型不是具体类型,而是数组类型,比如变量 y 的类型是 string | (() => void)

这在写项目时是不安全的,因为可以将 y 随时修改为字符串,同时也不会有友好的代码提示

function hj() {
    
    
    let a = 'hj'
    let b = (x: number, y: number): number => x + y
    return [a, b]
}

const [x, y] = hj() // 变量 y 的类型为 string | (() => void)

使用 as const 就可以很高效的解决上面的问题,可以得到具体的类型,来得到更安全的代码,同时会有更好的代码提示

const hj = () => {
    
    
    let a = 'hj'
    let b = (): void => {
    
    }
    return [a, b] as const
}
  
const [x, y] = hj() // 变量 y 的类型为 () => void

也可以使用泛型来得到具体的值类型

const func = <T extends any[]>(...args: T): T => {
    
    
    return args;
}
const hj = () => {
    
    
    const a: string = 'hj'
    const b: number = 2090
    return func(a, b)
}

const [r, e] = hj()

猜你喜欢

转载自blog.csdn.net/qq_41887214/article/details/125582856