Ts知识点-泛型和其他

五、泛型:指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定具体类型的一种特性

使用函数泛型:不能使用运算符操作泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
function createArray2<T>(value: T, count: number) {
const arr: Array<T> = []
for (let index = 0; index < count; index++) {
arr.push(value)
}
return arr
}
const arr3 = createArray2<number>(11, 3)
console.log(arr3[0].toFixed())
// console.log(arr3[0].split('')) // error
const arr4 = createArray2<string>('aa', 3)
console.log(arr4[0].split(''))
// console.log(arr4[0].toFixed()) // error

多个泛型参数的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
(() => {
function handleSwap<K, V>(a: K, b: V): [K, V] {
return [a, b]
}
const result = handleSwap<string, number>('abc', 123)
console.log(result[0].length, result[1].toFixed())

function name(a: any, b: any): any {
return [a, b]
}
const num = name(123.12, 'SAD')
console.log(num[0].toFixed());
})()

泛型接口:通过接口去约束函数或类

在定义接口时, 为接口中的属性或方法定义泛型类型 在使用接口时, 再指定具体的泛型类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
(() => {
// 需求:定义一个类来存储用户信息
// 通过一个类的实例对象调用相关方法可以添加多个信息对象,调用

// 定义一个泛型接口
interface IbaseCRUD<T> {
// Array<T>
data: T[]
add: (t: T) => void
getById: (id: number) => T
}
// 定义一个用户信息的类
class User {
id?: number //id主键自增 ?该属性可有可无
name: string //姓名
age: number //年龄

constructor(name, age) {
this.name = name
this.age = age
}
}
// 定一个类,针对用户信息对象进行增加查询的操作
// CRUD => 创建,读取,增加,删除
class UserCRUD implements IbaseCRUD<User> {
// 用来保存多个User类型的用户信息对象
data: User[] = []
// 增加用户信息对象 Math.random() 0~1的随机数
add(user: User): void {
user = { ...user, id: Date.now() + Math.random() }
this.data.push(user)
console.log('保存user', user.id)
}
// 查询直指定用户的id
getById(id: number): User {
return this.data.find(item => item.id === id)
}
}
const userCRUD = new UserCRUD()
userCRUD.add(new User('tom', 12))
userCRUD.add(new User('tom2', 13))
console.log(userCRUD.data)
})()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
(() => {
// 需求:定义一个类来存储用户信息
// 通过一个类的实例对象调用相关方法可以添加多个信息对象,调用

// 定义一个泛型接口
interface baseinfo<T> {
data:T[]
add:(t: T) => T
}
// 定义一个用户信息的类
class Person {
id?:number
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age = age
}
}
// 定一个类,针对用户信息对象进行增加查询的操作
class Listperson implements baseinfo<Person> {
data: Array<Person> = []
// 函数返回值的类型不是any或void,必须有返回值,return
add(person:Person):Person{
person = {...person,id:Date.now()+ Math.random()}
this.data.push(person)
return person
}
getperson(id:number):Person{
return this.data.find(item => item.id === id)
}
}
const listperson = new Listperson()
listperson.add(new Person('lisa',123))
const { id } = listperson.add(new Person('zahng',12))
console.log(listperson.data);
console.log(id,listperson.getperson(id));
})()

泛型类

在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(() => {
class GenericNumber<T> {
zeroValue: T
add: (x: T, y: T) => T
}
let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 0
myGenericNumber.add = function (x, y) {
return x + y
}
let myGenericString = new GenericNumber<string>()
myGenericString.zeroValue = 'abc'
myGenericString.add = function (x, y) {
return x + y
}
console.log(myGenericString.add(myGenericString.zeroValue, 'test'))
console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12))
})()

泛型约束

如果我们直接对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(() => {
// 没有泛型约束
function fn<T>(x: T): void {
// console.log(x.length) // error
}
function fn2(x: number[]): void {
console.log(x.length)
}
interface Lengthwise {
length: number
}

// 指定泛型约束
function fn3<T extends Lengthwise>(x: T): void {
console.log(x.length)
}
fn2([12, 125, 5412, 15, 54])
fn3([12, 125, 5412, 15, 54])
})()

六、 其它

声明文件

当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能

1
2
3
4
5
6
7
8
9
10
/*
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
声明语句: 如果需要ts对新的语法进行检查, 需要要加载了对应的类型说明代码
declare var jQuery: (selector: string) => any;
声明文件: 把声明语句放到一个单独的文件(jQuery.d.ts)中, ts会自动解析到项目中所有声明文件
下载声明文件: npm install @types/jquery --save-dev
*/

jQuery('#foo')
// ERROR: Cannot find name 'jQuery'.

需要使用 declare var 来定义它的类型

1
2
3
declare var jQuery: (selector: string) => any

jQuery('#foo')

declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。它编译结果是:

1
jQuery('#foo')

一般声明文件都会单独写成一个 xxx.d.ts 文件
创建 01_jQuery.d.ts, 将声明语句定义其中, TS 编译器会扫描并加载项目中所有的 TS 声明文件

1
declare var jQuery: (selector: string) => any
1
2
3
很多的第三方库都定义了对应的声明文件库, 库文件名一般为 @types/xxx, 可以在 https://www.npmjs.com/package/package 进行搜索

有的第三库在下载时就会自动下载对应的声明文件库(比如: webpack),有的可能需要单独下载(比如 jQuery/react)

内置对象

JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型
ECMAScript 的内置对象

1
2
3
4
5
6
7
8
9
10
11
/* 1. ECMAScript 的内置对象 */
let b: Boolean = new Boolean(1)
let n: Number = new Number(true)
let s: String = new String('abc')
let d: Date = new Date()
let r: RegExp = /^1/
let e: Error = new Error('error message')
// 以上都是对象
b = true
// let bb: boolean = new Boolean(2) // error

BOM 和 DOM 的内置对象

1
2
3
4
5
6
const div: HTMLElement = document.getElementById('test')
const divs: NodeList = document.querySelectorAll('div')
document.addEventListener('click', (event: MouseEvent) => {
console.dir(event.target)
})
const fragment: DocumentFragment = document.createDocumentFragment()

-------------本文结束感谢您的阅读-------------

我的传送门:个人网站GithubGitee