泛型 Generics
泛型指使用时才定义类型,即类型可以像参数一样定义,主要解决类、接口、函数的复用性,让它们可以处理多种类型。
基本使用
下面示例返回值类型是 any,这不是我们想要的,因为我们想要具体返回类型
function dump(arg: any) {
return arg
}
const fn = dump('tydumpling') // 类型为 any
const data = dump(true) // 类型为 any
使用了泛型定义后,返回值即为明确的类型
function dump<T>(arg: T): T {
return arg
}
const fn = dump < string > ('tydumpling')
如果调用时不指定类型系统也会自动推断类型
...
let fn = dump('tydumpling') //fn 类型为 string
...
类型继承
下面的代码是不严谨的,我们不需要处理数字,因为数字没有 length 属性,同时我们希望返回类型不是 any
function getLength(arg: any) {
return arg.length
}
console.log(getLength('tydumpling.com')) // 10
console.log(getLength(['tydumpling'])) // 1
console.log(getLength(18)) // undefined
泛型是不确定的类型,所以下面读取 length 属性将报错
function getLength<T>(arg: T): number {
return arg.length // 类型“T”上不存在属性“length”
}
我可以通过继承 extends
继承,让泛型定义包含 length
属性。
function getLength<T extends { length: number }>(arg: T): number {
return arg.length;
}
//或使用 interface 或 type
type LengthType = { length: number }
function getLengthAttribute<T extends }>(arg: T): number {
return arg.length;
}
如果你的类型只是字符串或数组,也可以使用联合类型
function getLength<T extends string | any[]>(arg: T): number {
return arg.length
}
console.log(getLength('tydumpling.com'))
console.log(getLength(['tydumpling', 'tydumpling']))
TS 也会自动推断,比如下面参数是 T[]
,TS
会推断为数组类型,所以这时候是存在 length
的,不会报错,此时T指的是数组类型。
function getLength<T>(arg: T[]): number {
return arg.length
}
getLength < string | number > (['tydumpling', 123])
将泛型理解为动态类型,他最终也会是一个类型,所以使用方式与我们其他类型一样的。比如下面的返回值类型,我们就返回了一个元组,包括泛型与数值类型
function getLength<T extends string>(arg: T): [T, number] {
return [arg, arg.length]
}
const fn = getLength < string > ('tydumpling.com')
类
使用泛型复用类
下面是对数值与字符串类型的集合进行管理,因为业务是一样的,所以下面的实现是重复的
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('tydumpling', 'tydumpling')
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 fn: User = { name: "tydumpling", age: 18 }
const userCollection = new Collection<User>()
userCollection.push(fn)
console.log(userCollection.shift());
接口结合泛型
下面的代码是不稳定的,我们的意图是传递用户数据,但没有类型约束情况下,可以传递任何类型
class User {
constructor(protected _user) { }
public get() {
return this._user
}
}
const instance = new User({ name: 'tydumpling' })
console.log(instance.get())
对类使用泛型处理后,可以保证传递与返回值的类型,并具有良好的代码提示
class User<T> {
constructor(protected _user: T) { }
public get(): T {
return this._user
}
}
interface UserInterface {
name: string, age: number
}
const instance = new User() < UserInterface > ({ name: 'tydumpling', age: 18 })
console.log(instance.get().age)
接口
下面对接口的类型使用泛型定义,比如 isLock 可以为 number
或boolean
,并对文章的评论内容进行定义。
这样处理代码会有严格类型约束,并有良好的代码提示
// 文章接口
interface articleInterface<T, B> {
title: string
isLock: B
comments: T[]
}
// 评论类型
interface CommentType {
comment: string
}
// 定义文章数据包含评论内容
const fn: articleInterface<boolean, CommentType> = {
title: 'tydumpling官网',
isLock: true,
comments: [
{ comment: '这是一个评论' }
]
}
console.log(fn)
值类型
下面解构得到的变量类型不是具体类型,面是数组类型,比如变量 y 的类型是 string | (() => void)
这在写项目时是不安全的,因为可以将 y 随时修改为字符串,同时也不会有友好的代码提示
function fn() {
const a = 'tydumpling'
const b = (x: number, y: number): number => x + y
return [a, b]
}
const [x, y] = fn() // 变量 y 的类型为 string | (() => void)
使用 as const 就可以很高效的解决上面的问题,可以得到具体的类型,来得到更安全的代码,同时会有更好的代码提示
function fn() {
const a = 'tydumpling'
const b = (): void => {}
return [a, b] as const
}
const [x, y] = fn() // 变量 y 的类型为 () => void
也可以使用泛型来得到具体的值类型
function fn() {
const a: string = 'tydumpling'
const b: number = 2090
return f(a, b)
}
function f<T extends any[]>(...args: T): T {
return args
}
const [r, e] = fn()