TypeScript全汇总

TS基本概念

TS,是 JavaScript 的超集

为什么要 TS

• 从编程语言的动静来区分,TypeScript 属于静态类型的编程语言,JavaScript 属于动态类型的编程语言
• 静态类型:编译期做类型检查
• 动态类型:执行期做类型检查

• 代码编译和代码执行的顺序:1 编译 2 执行
• 对于 JS 来说:需要等到代码真正去执行的时候才能发现错误(晚)
• 对于 TS 来说:在代码编译的时候(代码执行前)就可以发现错误(早)

并且,配合 VSCode 等开发工具,TS 可以提前到在编写代码的同时就发现代码中的错误,减少找 Bug、改 Bug 时间

TS基础

1. 类型注解

概念:类型注解是TypeScript的核心特性,用于为变量、函数参数、返回值等添加类型信息,提供编译时类型检查。

语法规则

  • 变量:变量名: 类型 = 值
  • 函数参数:参数名: 类型
  • 函数返回值:function 函数名(): 返回类型
  • 对象:{ 属性名: 类型 }

作用

  • 提供类型安全,在编译时发现错误
  • 增强代码可读性和可维护性
  • 提供更好的IDE支持和智能提示

基本类型注解

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
// 变量类型注解 - 明确指定变量类型
let name: string = '张三' // 字符串类型
let age: number = 25 // 数字类型
let isStudent: boolean = true // 布尔类型
let hobby: null = null // null类型
let address: undefined = undefined // undefined类型

// 函数参数和返回值类型注解 - 确保函数输入输出类型正确
function greet(name: string): string {
return `Hello, ${name}!`
}

// 函数表达式类型注解 - 箭头函数的类型声明
const add = (a: number, b: number): number => {
return a + b
}

// 数组类型注解 - 指定数组元素类型
let numbers: number[] = [1, 2, 3] // 数字数组
let names: Array<string> = ['张三', '李四'] // 字符串数组

// 对象类型注解 - 定义对象结构
let user: {
name: string
age: number
isStudent: boolean
} = {
name: '张三',
age: 25,
isStudent: true
}

可选参数和默认参数

概念:可选参数使用?标记,表示参数可以传入也可以不传入;默认参数使用=提供默认值。

语法规则

  • 可选参数:参数名?: 类型
  • 默认参数:参数名: 类型 = 默认值
  • 剩余参数:...参数名: 类型[]

使用场景

  • 可选参数:当某些参数不是必需时使用
  • 默认参数:为参数提供默认值,简化函数调用
  • 剩余参数:处理不定数量的参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 可选参数 - 使用?标记,参数可以不传
function greet(name: string, age?: number): string {
if (age) {
return `Hello, ${name}, you are ${age} years old!`
}
return `Hello, ${name}!`
}

// 默认参数 - 使用=提供默认值
function createUser(name: string, age: number = 18): object {
return { name, age }
}

// 剩余参数 - 使用...处理不定数量参数
function sum(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0)
}

函数重载

概念:函数重载允许同一个函数名有多个不同的函数签名,根据传入参数的类型或数量调用不同的实现。

语法规则

  • 重载声明:function 函数名(参数): 返回类型
  • 重载实现:function 函数名(参数: 联合类型): 返回类型

使用场景

  • 同一个函数需要处理不同类型的参数
  • 提供更精确的类型检查和更好的IDE提示
  • 简化API设计,一个函数名处理多种情况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 函数重载声明 - 定义多个函数签名
function format(value: string): string
function format(value: number): string
function format(value: boolean): string

// 函数重载实现 - 实际实现函数
function format(value: string | number | boolean): string {
if (typeof value === 'string') {
return value.toUpperCase()
} else if (typeof value === 'number') {
return value.toString()
} else {
return value ? 'true' : 'false'
}
}

// 使用重载 - 根据参数类型自动选择正确的重载
console.log(format('hello')) // 'HELLO'
console.log(format(123)) // '123'
console.log(format(true)) // 'true'

类型断言

概念:类型断言告诉TypeScript编译器某个值的具体类型,类似于其他语言中的类型转换,但不进行运行时检查。

语法规则

  • 值 as 类型 (推荐)
  • <类型>值 (不推荐,容易与JSX冲突)

使用场景

  • 当你比TypeScript更了解某个值的类型时
  • 处理any类型的值时
  • 处理联合类型时进行类型收窄
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 类型断言语法 - 使用as关键字
let someValue: any = 'this is a string'
let strLength: number = (someValue as string).length

// 另一种语法 - 使用<>语法(不推荐,容易与JSX冲突)
let strLength2: number = (<string>someValue).length

// 实际应用场景 - 处理联合类型
function getLength(value: string | number): number {
if ((value as string).length !== undefined) {
return (value as string).length
} else {
return value.toString().length
}
}

类型推断

概念:类型推断是TypeScript自动分析代码并推断出变量、函数参数、返回值等类型的能力,无需显式声明类型。

语法规则

  • 变量:let 变量名 = 值 (自动推断类型)
  • 函数:function 函数名(参数) { return 值 } (自动推断返回类型)
  • 对象:let 对象名 = { 属性: 值 } (自动推断对象结构)

使用场景

  • 简化代码,减少冗余的类型声明
  • 提高开发效率
  • 保持代码简洁性

注意:虽然类型推断很方便,但在复杂场景下建议显式声明类型以提高代码可读性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// TypeScript 自动推断类型 - 根据赋值推断
let name = '张三' // 推断为 string
let age = 25 // 推断为 number
let isStudent = true // 推断为 boolean

// 数组类型推断 - 根据数组元素推断
let numbers = [1, 2, 3] // 推断为 number[]

// 对象类型推断 - 根据对象属性推断
let user = {
name: '张三',
age: 25
} // 推断为 { name: string, age: number }

// 函数返回类型推断 - 根据return语句推断
function add(a: number, b: number) {
return a + b // 推断返回类型为 number
}

2. 基本类型 (Basic Types)

概念:TypeScript提供了多种基本数据类型,用于描述不同类型的数据。

语法规则

  • 原始类型:stringnumberbooleannullundefined
  • 数组类型:类型[]Array<类型>
  • 元组类型:[类型1, 类型2, ...]
  • 对象类型:{ 属性名: 类型 }

原始类型

1
2
3
4
5
6
7
8
9
10
11
12
13
// 基本类型
let name: string = '张三'
let age: number = 25
let isStudent: boolean = true
let hobby: null = null
let address: undefined = undefined

// 数组类型
let numbers: number[] = [1, 2, 3]
let names: Array<string> = ['张三', '李四']

// 元组类型
let person: [string, number] = ['张三', 25]

对象类型

1
2
3
4
5
6
7
8
9
10
// 对象类型定义
let user: {
name: string
age: number
isStudent: boolean
} = {
name: '张三',
age: 25,
isStudent: true
}

3. 联合类型和交叉类型 (Union and Intersection Types)

概念:联合类型和交叉类型是TypeScript中组合类型的两种重要方式,用于处理复杂的类型关系。

语法规则

  • 联合类型:类型1 | 类型2 | 类型3
  • 交叉类型:类型1 & 类型2 & 类型3

作用

  • 联合类型:表示值可以是几种类型中的任意一种
  • 交叉类型:表示值必须同时满足多个类型的条件

使用场景

  • 联合类型:处理多种可能的类型,API返回多种类型
  • 交叉类型:组合多个接口,混入功能

联合类型 (Union Types)

概念:联合类型表示一个值可以是几种类型中的任意一种,使用 | 分隔。

语法规则类型1 | 类型2 | 类型3

特点

  • 值可以是其中任意一种类型
  • 只能访问所有类型共有的属性或方法
  • 需要进行类型收窄才能访问特定类型的属性
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
44
45
46
47
48
49
50
51
52
// 基本联合类型
type StringOrNumber = string | number

function formatValue(value: StringOrNumber): string {
if (typeof value === 'string') {
// 类型收窄后,可以访问string的方法
return value.toUpperCase()
} else {
// 类型收窄后,可以访问number的方法
return value.toString()
}
}

// 字面量联合类型
type Status = 'pending' | 'success' | 'error'

function handleStatus(status: Status) {
switch (status) {
case 'pending':
console.log('处理中...')
break
case 'success':
console.log('成功!')
break
case 'error':
console.log('错误!')
break
}
}

// 对象联合类型
type Circle = {
kind: 'circle'
radius: number
}

type Rectangle = {
kind: 'rectangle'
width: number
height: number
}

type Shape = Circle | Rectangle

function getArea(shape: Shape): number {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius * shape.radius
case 'rectangle':
return shape.width * shape.height
}
}

交叉类型 (Intersection Types)

概念:交叉类型表示一个值必须同时满足多个类型的条件,使用 & 分隔。

语法规则类型1 & 类型2 & 类型3

特点

  • 值必须同时满足所有类型的条件
  • 可以访问所有类型的属性和方法
  • 常用于组合多个接口或类型
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
44
45
46
47
48
49
50
51
// 基本交叉类型
type Person = {
name: string
age: number
} & {
email: string
phone: string
}

let person: Person = {
name: '张三',
age: 25,
email: 'zhangsan@example.com',
phone: '13800138000'
}

// 接口交叉
interface Flyable {
fly(): void
}

interface Swimmable {
swim(): void
}

type Duck = Flyable & Swimmable

let duck: Duck = {
fly() {
console.log('鸭子飞')
},
swim() {
console.log('鸭子游泳')
}
}

// 函数交叉类型
type Logger = {
log(message: string): void
} & {
error(message: string): void
}

let logger: Logger = {
log(message: string) {
console.log(`LOG: ${message}`)
},
error(message: string) {
console.error(`ERROR: ${message}`)
}
}

联合类型 vs 交叉类型

| 特性 | 联合类型 (|) | 交叉类型 (&) |
|——|—————-|—————-|
| 含义 | 值可以是其中任意一种类型 | 值必须同时满足所有类型 |
| 访问属性 | 只能访问共有属性 | 可以访问所有属性 |
| 类型收窄 | 需要类型收窄 | 不需要类型收窄 |
| 使用场景 | 处理多种可能的情况 | 组合多个类型 |

类型守卫 (Type Guards)

概念:类型守卫是运行时检查,用于在运行时确定值的类型。

语法规则function 函数名(参数): 参数 is 类型

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
// 类型守卫函数
function isString(value: any): value is string {
return typeof value === 'string'
}

function isNumber(value: any): value is number {
return typeof value === 'number'
}

// 使用类型守卫
function processValue(value: string | number) {
if (isString(value)) {
// 这里 value 被推断为 string 类型
console.log(value.toUpperCase())
} else if (isNumber(value)) {
// 这里 value 被推断为 number 类型
console.log(value.toFixed(2))
}
}

// 使用 in 操作符进行类型守卫
type Bird = {
fly(): void
}

type Fish = {
swim(): void
}

function move(animal: Bird | Fish) {
if ('fly' in animal) {
// 这里 animal 被推断为 Bird 类型
animal.fly()
} else {
// 这里 animal 被推断为 Fish 类型
animal.swim()
}
}

4. 接口 (Interface)

概念:接口是TypeScript中定义对象结构的一种方式,它描述了对象应该具有的属性和方法,但不提供具体实现。

语法规则

  • 基本接口:interface 接口名 { 属性名: 类型 }
  • 可选属性:属性名?: 类型
  • 只读属性:readonly 属性名: 类型
  • 函数接口:interface 接口名 { (参数): 返回类型 }
  • 接口继承:interface 接口名 extends 父接口 { }

作用

  • 定义对象的结构和契约
  • 提供类型检查和智能提示
  • 提高代码的可维护性和可读性
  • 支持接口继承和实现

基本接口

1
2
3
4
5
6
7
8
9
10
11
12
interface User {
name: string
age: number
email?: string // 可选属性
readonly id: number // 只读属性
}

let user: User = {
name: '张三',
age: 25,
id: 1
}

函数接口

1
2
3
4
5
6
7
interface SearchFunc {
(source: string, subString: string): boolean
}

let mySearch: SearchFunc = function(source: string, subString: string) {
return source.indexOf(subString) > -1
}

接口继承

1
2
3
4
5
6
7
8
9
10
11
12
interface Shape {
color: string
}

interface Square extends Shape {
sideLength: number
}

let square: Square = {
color: 'red',
sideLength: 10
}

5. 类型别名 (Type)

概念:类型别名允许为任何类型创建一个新名称,提高代码的可读性和复用性。

语法规则

  • 基本类型别名:type 别名名 = 类型
  • 联合类型:type 别名名 = 类型1 | 类型2
  • 交叉类型:type 别名名 = 类型1 & 类型2
  • 对象类型:type 别名名 = { 属性名: 类型 }

使用场景

  • 简化复杂的类型定义
  • 创建联合类型和交叉类型
  • 提高代码可读性
  • 复用类型定义

6. 泛型 (Generics)

概念:泛型允许在定义函数、接口或类时不预先指定具体的类型,而在使用时再指定类型,提高代码的复用性和灵活性。

语法规则

  • 泛型函数:function 函数名<T>(参数: T): T
  • 泛型接口:interface 接口名<T> { }
  • 泛型类:class 类名<T> { }
  • 泛型约束:<T extends 约束类型>

使用场景

  • 创建可复用的组件
  • 保持类型安全
  • 提高代码灵活性
  • 避免使用any类型

基本泛型使用

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
// 泛型函数 - 最基础的泛型使用
function identity<T>(arg: T): T {
return arg
}

let output = identity<string>('hello') // 显式指定类型
let output2 = identity(123) // 类型推断

// 泛型接口 - 定义可复用的接口
interface GenericIdentityFn<T> {
(arg: T): T
}

let myIdentity: GenericIdentityFn<number> = identity

// 泛型类 - 创建可复用的类
class GenericNumber<T> {
zeroValue: T
add: (x: T, y: T) => T

constructor(zeroValue: T, addFn: (x: T, y: T) => T) {
this.zeroValue = zeroValue
this.add = addFn
}
}

let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y)
let myGenericString = new GenericNumber<string>('', (x, y) => x + y)

多泛型参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 多个泛型参数
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}

let swapped = swap<string, number>(['hello', 42]) // [42, 'hello']

// 泛型接口多参数
interface KeyValuePair<K, V> {
key: K
value: V
}

let pair: KeyValuePair<string, number> = {
key: 'age',
value: 25
}

泛型默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 泛型默认值 - TypeScript 2.3+
interface ApiResponse<T = any> {
data: T
status: number
message: string
}

// 使用默认类型
let response1: ApiResponse = { data: 'hello', status: 200, message: 'OK' }

// 指定具体类型
let response2: ApiResponse<User> = {
data: { id: 1, name: 'John' },
status: 200,
message: 'OK'
}

泛型与数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 泛型数组操作
function getFirstElement<T>(arr: T[]): T | undefined {
return arr[0]
}

function getLastElement<T>(arr: T[]): T | undefined {
return arr[arr.length - 1]
}

let numbers = [1, 2, 3, 4, 5]
let first = getFirstElement(numbers) // number | undefined
let last = getLastElement(numbers) // number | undefined

// 泛型数组过滤
function filterArray<T>(arr: T[], predicate: (item: T) => boolean): T[] {
return arr.filter(predicate)
}

let evenNumbers = filterArray(numbers, n => n % 2 === 0) // number[]

泛型与Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 泛型Promise
function fetchData<T>(url: string): Promise<T> {
return fetch(url).then(response => response.json())
}

// 使用泛型Promise
fetchData<User[]>('/api/users').then(users => {
// users 的类型是 User[]
console.log(users)
})

// 泛型异步函数
async function getData<T>(url: string): Promise<T> {
const response = await fetch(url)
return response.json()
}

// 使用泛型异步函数
const users = await getData<User[]>('/api/users')

泛型约束 (Generic Constraints)

概念:泛型约束允许我们限制泛型参数必须满足某些条件,使用 extends 关键字。

语法规则<T extends 约束类型>

作用

  • 限制泛型参数的类型范围
  • 在泛型函数中访问约束类型的属性
  • 提供更精确的类型检查
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 基本泛型约束
interface Lengthwise {
length: number
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length) // 可以访问length属性
return arg
}

loggingIdentity('hello') // OK - string有length属性
loggingIdentity([1, 2, 3]) // OK - array有length属性
loggingIdentity(123) // Error - number没有length属性

// 多个约束
interface Printable {
print(): void
}

interface Serializable {
serialize(): string
}

function process<T extends Printable & Serializable>(item: T): void {
item.print() // 可以调用print方法
item.serialize() // 可以调用serialize方法
}

// 使用keyof约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}

let person = { name: '张三', age: 25 }
let name = getProperty(person, 'name') // OK
let age = getProperty(person, 'age') // OK
let invalid = getProperty(person, 'email') // Error - email不是person的属性

// 条件约束
type NonNullable<T> = T extends null | undefined ? never : T

function processValue<T>(value: NonNullable<T>): void {
// value不会是null或undefined
}

// 泛型约束与函数重载
function createArray<T extends string | number>(length: number, value: T): T[] {
return Array(length).fill(value)
}

let stringArray = createArray(3, 'hello') // string[]
let numberArray = createArray(3, 42) // number[]

// 泛型约束与索引签名
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}

let person = { name: 'John', age: 30, city: 'New York' }
let name = getProperty(person, 'name') // string
let age = getProperty(person, 'age') // number
// let invalid = getProperty(person, 'email') // Error

// 泛型约束与构造函数
function createInstance<T extends new (...args: any[]) => any>(
constructor: T,
...args: ConstructorParameters<T>
): InstanceType<T> {
return new constructor(...args)
}

class Person {
constructor(public name: string, public age: number) {}
}

let personInstance = createInstance(Person, 'John', 30) // Person

泛型实用技巧

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 1. 泛型与工具类型结合
type Optional<T> = {
[K in keyof T]?: T[K]
}

type Required<T> = {
[K in keyof T]-?: T[K]
}

// 2. 泛型与条件类型结合
type ApiResponse<T> = T extends 'user' ? User :
T extends 'post' ? Post :
T extends 'comment' ? Comment :
never

// 3. 泛型与映射类型结合
type CustomPartial<T> = {
[P in keyof T]?: T[P]
}

type CustomReadonly<T> = {
readonly [P in keyof T]: T[P]
}

// 4. 泛型工厂函数
function createFactory<T>(type: new (...args: any[]) => T) {
return (...args: any[]): T => new type(...args)
}

// 5. 泛型缓存
class Cache<T> {
private cache = new Map<string, T>()

get(key: string): T | undefined {
return this.cache.get(key)
}

set(key: string, value: T): void {
this.cache.set(key, value)
}

has(key: string): boolean {
return this.cache.has(key)
}
}

// 6. 泛型事件系统
type EventMap = {
'user:created': { id: number; name: string }
'user:updated': { id: number; changes: Partial<User> }
'user:deleted': { id: number }
}

class EventEmitter<T extends Record<string, any>> {
private listeners = new Map<keyof T, Array<(data: T[keyof T]) => void>>()

on<K extends keyof T>(event: K, listener: (data: T[K]) => void): void {
if (!this.listeners.has(event)) {
this.listeners.set(event, [])
}
this.listeners.get(event)!.push(listener)
}

emit<K extends keyof T>(event: K, data: T[K]): void {
const eventListeners = this.listeners.get(event)
if (eventListeners) {
eventListeners.forEach(listener => listener(data))
}
}
}

// 使用泛型事件系统
const emitter = new EventEmitter<EventMap>()
emitter.on('user:created', (data) => {
console.log(`User created: ${data.name}`) // data 类型是 { id: number; name: string }
})

7. 类 (Class)

概念:类是面向对象编程的基础,TypeScript中的类支持访问修饰符、继承、抽象类等特性。

语法规则

  • 基本类:class 类名 { }
  • 访问修饰符:publicprivateprotected
  • 继承:class 子类 extends 父类 { }
  • 抽象类:abstract class 类名 { }
  • 抽象方法:abstract 方法名(): 返回类型

使用场景

  • 面向对象编程
  • 封装数据和行为
  • 实现继承和多态
  • 创建抽象类

基本类定义

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
class Person {
// 属性声明
name: string
age: number

// 构造函数
constructor(name: string, age: number) {
this.name = name
this.age = age
}

// 方法
greet(): string {
return `Hello, I'm ${this.name}`
}

// 静态方法
static createAdult(name: string): Person {
return new Person(name, 18)
}
}

// 使用类
let person = new Person('张三', 25)
console.log(person.greet()) // "Hello, I'm 张三"

// 使用静态方法
let adult = Person.createAdult('李四')

访问修饰符 (Access Modifiers)

概念:访问修饰符控制类成员的可访问性,包括 publicprivateprotected

语法规则

  • public - 公共的,可以在任何地方访问
  • private - 私有的,只能在类内部访问
  • protected - 受保护的,只能在类内部和子类中访问

作用

  • 封装数据,隐藏内部实现
  • 控制接口的暴露程度
  • 提高代码的安全性和可维护性
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
44
45
46
47
48
49
50
51
class Animal {
public name: string // 公共属性 - 任何地方都可以访问
private age: number // 私有属性 - 只能在类内部访问
protected color: string // 受保护属性 - 只能在类内部和子类中访问

constructor(name: string, age: number, color: string) {
this.name = name
this.age = age
this.color = color
}

// 公共方法
public getName(): string {
return this.name
}

// 私有方法
private getAge(): number {
return this.age
}

// 受保护方法
protected getColor(): string {
return this.color
}
}

class Dog extends Animal {
constructor(name: string, age: number, color: string) {
super(name, age, color)
}

public getInfo(): string {
// 可以访问公共属性
console.log(this.name)

// 可以访问受保护属性
console.log(this.color)

// 不能访问私有属性
// console.log(this.age) // Error

return `${this.name} is ${this.color}`
}
}

let dog = new Dog('旺财', 3, '棕色')
console.log(dog.name) // OK - 公共属性
console.log(dog.getInfo()) // OK - 公共方法
// console.log(dog.age) // Error - 私有属性
// console.log(dog.color) // Error - 受保护属性

抽象类 (Abstract Classes)

概念:抽象类是不能被实例化的类,用于定义子类必须实现的接口和共同行为。

语法规则

  • abstract class 类名 { } - 定义抽象类
  • abstract 方法名(): 返回类型 - 定义抽象方法
  • abstract 属性名: 类型 - 定义抽象属性

特点

  • 不能被直接实例化
  • 可以包含抽象方法和具体方法
  • 子类必须实现所有抽象方法
  • 用于定义通用接口和共同行为

使用场景

  • 定义通用接口
  • 强制子类实现特定方法
  • 提供共同的基础功能
  • 实现模板方法模式
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// 抽象类定义
abstract class Animal {
// 抽象属性
abstract species: string

// 抽象方法 - 子类必须实现
abstract makeSound(): void

// 具体方法 - 子类可以继承
move(): void {
console.log('Moving...')
}

// 具体方法 - 子类可以继承
sleep(): void {
console.log('Sleeping...')
}
}

// 子类实现抽象类
class Dog extends Animal {
species: string = 'Canine'

// 必须实现抽象方法
makeSound(): void {
console.log('Woof!')
}

// 可以添加自己的方法
wagTail(): void {
console.log('Wagging tail...')
}
}

class Cat extends Animal {
species: string = 'Feline'

// 必须实现抽象方法
makeSound(): void {
console.log('Meow!')
}

// 可以添加自己的方法
purr(): void {
console.log('Purring...')
}
}

// 使用抽象类
let dog = new Dog()
dog.makeSound() // "Woof!"
dog.move() // "Moving..."
dog.sleep() // "Sleeping..."
dog.wagTail() // "Wagging tail..."

let cat = new Cat()
cat.makeSound() // "Meow!"
cat.move() // "Moving..."
cat.sleep() // "Sleeping..."
cat.purr() // "Purring..."

// 不能直接实例化抽象类
// let animal = new Animal() // Error - 抽象类不能被实例化

// 多态使用
function makeAnimalSound(animal: Animal): void {
animal.makeSound() // 多态调用
}

makeAnimalSound(dog) // "Woof!"
makeAnimalSound(cat) // "Meow!"

8. 枚举 (Enum)

概念:枚举是一组命名常量的集合,提供了一种定义命名常量的方式。

语法规则

  • 数字枚举:enum 枚举名 { 成员1, 成员2 }
  • 字符串枚举:enum 枚举名 { 成员1 = '值1', 成员2 = '值2' }
  • 使用枚举:枚举名.成员名

使用场景

  • 定义一组相关的常量
  • 提高代码可读性
  • 避免魔法数字
  • 提供类型安全

数字枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 基本数字枚举
enum Direction {
Up = 1, // 从1开始
Down, // 自动递增为2
Left, // 自动递增为3
Right // 自动递增为4
}

// 使用数字枚举
let direction: Direction = Direction.Up
console.log(direction) // 1

// 通过值获取名称
console.log(Direction[1]) // "Up"
console.log(Direction[2]) // "Down"

字符串枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
// 字符串枚举
enum Color {
Red = 'red',
Green = 'green',
Blue = 'blue'
}

// 使用字符串枚举
let color: Color = Color.Red
console.log(color) // "red"

// 字符串枚举不能反向查找
// console.log(Color['red']) // undefined

混合枚举

1
2
3
4
5
// 混合枚举(不推荐)
enum Mixed {
No = 0,
Yes = 'yes'
}

常量枚举

1
2
3
4
5
6
7
8
9
10
// 常量枚举 - 编译时会被内联
const enum Status {
Pending,
Success,
Error
}

// 使用常量枚举
let status: Status = Status.Success
// 编译后:let status = 1

9. 高级类型 (Advanced Types)

概念:高级类型是TypeScript提供的复杂类型系统,包括条件类型、映射类型等。

语法规则

  • 条件类型:T extends U ? X : Y
  • 映射类型:{ [K in keyof T]: NewType }
  • 模板字面量类型:`template string`

使用场景

  • 复杂的类型操作
  • 类型转换和映射
  • 高级类型编程

条件类型 (Conditional Types)

概念:条件类型根据条件选择不同的类型,类似于三元运算符。

语法规则T extends U ? X : Y

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 基本条件类型
type IsString<T> = T extends string ? true : false

type Test1 = IsString<string> // true
type Test2 = IsString<number> // false

// 条件类型与联合类型
type NonNullable<T> = T extends null | undefined ? never : T

type Test3 = NonNullable<string | null> // string
type Test4 = NonNullable<number | undefined> // number

// 条件类型与infer
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never

type Test5 = ReturnType<() => string> // string
type Test6 = ReturnType<() => number> // number

映射类型 (Mapped Types)

概念:映射类型基于旧类型创建新类型,通过遍历旧类型的属性来生成新类型。

语法规则{ [K in keyof T]: NewType }

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
// 基本映射类型
type CustomPartial<T> = {
[K in keyof T]?: T[K]
}

type CustomReadonly<T> = {
readonly [K in keyof T]: T[K]
}

// 使用映射类型
interface User {
name: string
age: number
email: string
}

type PartialUser = CustomPartial<User>
// { name?: string; age?: number; email?: string }

type ReadonlyUser = CustomReadonly<User>
// { readonly name: string; readonly age: number; readonly email: string }

// 键重映射
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}

type UserGetters = Getters<User>
// { getName: () => string; getAge: () => number; getEmail: () => string }

模板字面量类型 (Template Literal Types)

概念:模板字面量类型使用模板字符串语法创建字符串字面量类型。

语法规则`template string`

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 基本模板字面量类型
type EventName<T extends string> = `on${Capitalize<T>}`

type ClickEvent = EventName<'click'> // 'onClick'
type ChangeEvent = EventName<'change'> // 'onChange'

// 复杂的模板字面量类型
type ApiEndpoint<T extends string> = `/api/${T}`

type UserEndpoint = ApiEndpoint<'users'> // '/api/users'
type ProductEndpoint = ApiEndpoint<'products'> // '/api/products'

// 模板字面量类型与条件类型结合
type GetPropertyType<T, K extends string> =
K extends keyof T ? T[K] : never

type UserName = GetPropertyType<User, 'name'> // string
type UserAge = GetPropertyType<User, 'age'> // number

10. 模块系统 (Module System)

概念:模块系统允许将代码分割成多个文件,每个文件可以导出和导入功能。

语法规则

  • 命名导出:export const/function 名称
  • 默认导出:export default 值
  • 命名导入:import { 名称 } from '模块'
  • 默认导入:import 名称 from '模块'
  • 全部导入:import * as 名称 from '模块'

使用场景

  • 代码组织和分割
  • 功能复用
  • 避免全局污染
  • 提高代码可维护性
1
2
3
4
5
6
7
8
9
10
11
12
13
// 命名导出
export const name = 'TypeScript'
export function greet(name: string): string {
return `Hello, ${name}!`
}

// 默认导出
export default class User {
name: string
constructor(name: string) {
this.name = name
}
}

导入

1
2
3
4
5
6
7
8
// 命名导入
import { name, greet } from './module'

// 默认导入
import User from './module'

// 全部导入
import * as utils from './utils'

11. 实用工具类型 (Utility Types)

概念:实用工具类型是TypeScript内置的类型操作工具,用于创建新的类型。

语法规则

  • Partial<T> - 所有属性变为可选
  • Required<T> - 所有属性变为必需
  • Pick<T, K> - 选择特定属性
  • Omit<T, K> - 排除特定属性
  • Record<K, V> - 创建记录类型

使用场景

  • 类型转换和操作
  • 创建新的类型
  • 简化复杂类型定义
  • 提高类型复用性
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
44
45
46
47
48
49
50
51
52
interface User {
id: number
name: string
email: string
age: number
}

// Partial - 所有属性变为可选
type PartialUser = Partial<User>
// { id?: number; name?: string; email?: string; age?: number }

// Required - 所有属性变为必需
type RequiredUser = Required<User>
// { id: number; name: string; email: string; age: number }

// Pick - 选择特定属性
type UserName = Pick<User, 'name'>
// { name: string }

type UserBasicInfo = Pick<User, 'id' | 'name'>
// { id: number; name: string }

// Omit - 排除特定属性
type UserWithoutEmail = Omit<User, 'email'>
// { id: number; name: string; age: number }

type UserWithoutId = Omit<User, 'id'>
// { name: string; email: string; age: number }

// Record - 创建记录类型
type UserRecord = Record<string, User>
// { [key: string]: User }

type StatusRecord = Record<'pending' | 'success' | 'error', string>
// { pending: string; success: string; error: string }

// 实际使用示例
function updateUser(id: number, updates: Partial<User>): void {
// updates 可以是 User 的任何子集
console.log(`Updating user ${id} with:`, updates)
}

function createUser(userData: Omit<User, 'id'>): User {
return {
id: Math.random(),
...userData
}
}

function getUserName(user: Pick<User, 'name'>): string {
return user.name
}

12. 配置文件 (Configuration)

概念:TypeScript配置文件用于控制编译器的行为和选项。

语法规则

  • 配置文件:tsconfig.json
  • 编译选项:"compilerOptions": { }
  • 包含文件:"include": ["路径"]
  • 排除文件:"exclude": ["路径"]

使用场景

  • 控制编译行为
  • 指定编译目标
  • 配置模块系统
  • 设置严格模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

13. 最佳实践 (Best Practices)

概念:TypeScript开发的最佳实践和推荐做法。

语法规则

  • 严格模式:"strict": true
  • 类型声明:let 变量名: 类型 = 值
  • 接口优先:interface 接口名 { }
  • 避免any:使用具体类型

使用场景

  • 提高代码质量
  • 减少运行时错误
  • 提高开发效率
  • 团队协作

推荐做法

  1. 启用严格模式 - 在tsconfig.json中设置"strict": true
  2. 使用接口定义对象结构 - 优先使用interface而不是type
  3. 合理使用泛型 - 提高代码复用性和类型安全
  4. 使用类型守卫 - 确保类型安全
  5. 避免使用any - 尽量使用具体类型
  6. 使用工具类型 - 利用TypeScript内置的工具类型

14. 装饰器 (Decorators)

概念:装饰器是一种特殊类型的声明,可以附加到类、方法、属性或参数上,用于修改或增强它们的行为。

语法规则

  • 类装饰器:@装饰器名 class 类名 { }
  • 方法装饰器:@装饰器名 方法名() { }
  • 属性装饰器:@装饰器名 属性名: 类型
  • 参数装饰器:方法名(@装饰器名 参数: 类型) { }

使用场景

  • 元编程和反射
  • 框架开发(如Angular)
  • 日志记录和性能监控
  • 依赖注入
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 类装饰器
function sealed(constructor: Function) {
Object.seal(constructor)
Object.seal(constructor.prototype)
}

@sealed
class Greeter {
greeting: string
constructor(message: string) {
this.greeting = message
}
greet() {
return "Hello, " + this.greeting
}
}

// 方法装饰器
function log(target: any, propertyName: string, descriptor: PropertyDescriptor) {
const method = descriptor.value
descriptor.value = function (...args: any[]) {
console.log(`调用方法: ${propertyName}`)
return method.apply(this, args)
}
}

class Calculator {
@log
add(a: number, b: number): number {
return a + b
}
}

// 属性装饰器
function format(target: any, propertyKey: string) {
let value = target[propertyKey]

const getter = function() {
return value
}

const setter = function(newVal: string) {
value = newVal.toUpperCase()
}

Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true
})
}

class Person {
@format
name: string = 'john'
}

let person = new Person()
person.name = 'jane'
console.log(person.name) // "JANE"

15. 命名空间 (Namespaces)

概念:命名空间提供了一种组织代码的方式,避免全局命名冲突。

语法规则

  • 定义命名空间:namespace 命名空间名 { }
  • 导出成员:export 成员名
  • 使用命名空间:命名空间名.成员名

使用场景

  • 组织相关代码
  • 避免命名冲突
  • 模块化开发
  • 向后兼容
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
// 定义命名空间
namespace MyMath {
export function add(a: number, b: number): number {
return a + b
}

export function subtract(a: number, b: number): number {
return a - b
}

export namespace Advanced {
export function multiply(a: number, b: number): number {
return a * b
}
}
}

// 使用命名空间
let result1 = MyMath.add(5, 3) // 8
let result2 = MyMath.Advanced.multiply(4, 2) // 8

// 命名空间合并
namespace MyMath {
export function divide(a: number, b: number): number {
return a / b
}
}

let result3 = MyMath.divide(10, 2) // 5

16. 声明文件 (Declaration Files)

概念:声明文件用于描述JavaScript库的类型信息,以.d.ts结尾。

语法规则

  • 全局声明:declare global { }
  • 模块声明:declare module '模块名' { }
  • 类型声明:declare type 类型名 = 类型

使用场景

  • 为JavaScript库添加类型支持
  • 描述第三方库的API
  • 提供类型定义
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
// 全局声明
declare global {
interface Window {
myCustomProperty: string
}
}

// 模块声明
declare module 'lodash' {
export function chunk<T>(array: T[], size: number): T[][]
export function debounce<T extends (...args: any[]) => any>(
func: T,
wait: number
): T
}

// 类型声明
declare type MyCustomType = {
name: string
value: number
}

// 使用声明
window.myCustomProperty = 'hello'
import { chunk, debounce } from 'lodash'

17. 错误处理 (Error Handling)

概念:TypeScript提供了多种错误处理机制,包括类型错误、运行时错误等。

语法规则

  • 类型错误:编译时检查
  • 运行时错误:使用try-catch
  • 自定义错误:继承Error类

使用场景

  • 处理类型不匹配
  • 处理运行时异常
  • 提供错误信息
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
44
45
46
47
48
49
50
// 类型错误处理
function processValue(value: string | number): string {
if (typeof value === 'string') {
return value.toUpperCase()
} else if (typeof value === 'number') {
return value.toString()
} else {
// 这里永远不会执行,但TypeScript会检查
throw new Error('Invalid value type')
}
}

// 运行时错误处理
function divide(a: number, b: number): number {
try {
if (b === 0) {
throw new Error('Division by zero')
}
return a / b
} catch (error) {
console.error('Error:', error.message)
return 0
}
}

// 自定义错误类
class ValidationError extends Error {
constructor(message: string, public field: string) {
super(message)
this.name = 'ValidationError'
}
}

function validateUser(user: { name: string; age: number }): void {
if (!user.name) {
throw new ValidationError('Name is required', 'name')
}
if (user.age < 0) {
throw new ValidationError('Age must be positive', 'age')
}
}

// 使用自定义错误
try {
validateUser({ name: '', age: -1 })
} catch (error) {
if (error instanceof ValidationError) {
console.error(`Validation error in ${error.field}: ${error.message}`)
}
}

18. 性能优化 (Performance Optimization)

概念:TypeScript提供了多种性能优化技术,包括类型优化、编译优化等。

语法规则

  • 类型优化:使用具体类型
  • 编译优化:配置tsconfig.json
  • 运行时优化:避免类型检查

使用场景

  • 提高编译速度
  • 减少运行时开销
  • 优化类型检查
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
// 类型优化
// 避免使用any
function processData(data: any): any { // 不推荐
return data
}

// 使用具体类型
function processData<T>(data: T): T { // 推荐
return data
}

// 使用类型断言优化
function getElement(id: string): HTMLElement {
return document.getElementById(id) as HTMLElement
}

// 使用常量断言
const colors = ['red', 'green', 'blue'] as const
type Color = typeof colors[number] // 'red' | 'green' | 'blue'

// 使用satisfies操作符(TypeScript 4.9+)
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000
} satisfies {
apiUrl: string
timeout: number
}

// 使用const断言
const point = { x: 10, y: 20 } as const
type Point = typeof point // { readonly x: 10; readonly y: 20 }

📝 总结

TypeScript 是一个强大的 JavaScript 超集,为 JavaScript 添加了静态类型系统。通过本指南,我们学习了:

🎯 核心概念

  • 类型注解 - TypeScript 的基础,提供编译时类型检查
  • 接口和类型别名 - 定义对象结构和类型
  • 泛型 - 创建可复用的类型安全代码
  • - 面向对象编程支持

🚀 高级特性

  • 联合类型和交叉类型 - 处理复杂类型关系
  • 条件类型和映射类型 - 类型级别的编程
  • 模板字面量类型 - 字符串类型操作
  • 装饰器 - 元编程和框架开发

🛠️ 实用工具

  • 模块系统 - 代码组织和分割
  • 声明文件 - 为 JavaScript 库添加类型支持
  • 配置文件 - 控制编译行为
  • 错误处理 - 类型安全和运行时错误处理

💡 最佳实践

  1. 启用严格模式 - 获得最佳类型检查
  2. 使用接口定义对象结构 - 提高代码可读性
  3. 合理使用泛型 - 提高代码复用性
  4. 避免使用 any - 保持类型安全
  5. 使用工具类型 - 利用内置类型工具
  6. 编写声明文件 - 为第三方库提供类型支持