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()


第六章:装饰器 Decorators

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__畫戟__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值