TypeScript 是 JavaScript 的超集,为 JavaScript 添加了静态类型系统。它让大型项目更易维护,代码更健壮,开发体验更好。
一、TypeScript 是什么?
1.1 核心概念
// JavaScript
let name = "张三"
name = 123 // 可以,但可能导致运行时错误
// TypeScript
let name: string = "张三"
name = 123 // ❌ 编译时报错:不能将类型"number"分配给类型"string"
1.2 为什么选择 TypeScript?
- 类型安全:编译时发现错误,减少运行时错误
- 更好的 IDE 支持:智能提示、代码补全、重构
- 代码可读性:明确的类型注解让代码意图更清晰
- 渐进式采用:可以在现有 JavaScript 项目中逐步引入
二、快速开始
2.1 安装 TypeScript
# 全局安装
npm install -g typescript
# 或作为项目依赖
npm install --save-dev typescript
# 检查版本
tsc --version
2.2 第一个 TypeScript 程序
// hello.ts
function greet(name: string): string {
return `Hello, ${name}!`
}
console.log(greet("TypeScript"))
编译并运行:
# 编译
tsc hello.ts
# 运行
node hello.js
TypeScript 快速入门指南
TypeScript 是 JavaScript 的超集,为 JavaScript 添加了静态类型系统。它让大型项目更易维护,代码更健壮,开发体验更好。
一、TypeScript 是什么?
1.1 核心概念
// JavaScript
let name = "张三"
name = 123 // 可以,但可能导致运行时错误
// TypeScript
let name: string = "张三"
name = 123 // ❌ 编译时报错:不能将类型"number"分配给类型"string"
1.2 为什么选择 TypeScript?
- 类型安全:编译时发现错误,减少运行时错误
- 更好的 IDE 支持:智能提示、代码补全、重构
- 代码可读性:明确的类型注解让代码意图更清晰
- 渐进式采用:可以在现有 JavaScript 项目中逐步引入
二、快速开始
2.1 安装 TypeScript
# 全局安装
npm install -g typescript
# 或作为项目依赖
npm install --save-dev typescript
# 检查版本
tsc --version
2.2 第一个 TypeScript 程序
// hello.ts
function greet(name: string): string {
return `Hello, ${name}!`
}
console.log(greet("TypeScript"))
编译并运行:
# 编译
tsc hello.ts
# 运行
node hello.js
三、基础类型系统
3.1 基本类型
// 字符串
let name: string = "张三"
// 数字
let age: number = 25
let price: number = 99.99
// 布尔值
let isStudent: boolean = true
// 数组
let numbers: number[] = [1, 2, 3]
let names: Array<string> = ["张三", "李四"]
// 元组
let person: [string, number] = ["张三", 25]
// 枚举
enum Color {
Red,
Green,
Blue
}
let color: Color = Color.Green
// Any(尽量少用)
let anything: any = "可以是任何类型"
anything = 123
anything = true
// Void(无返回值)
function logMessage(): void {
console.log("This is a message")
}
// Null 和 Undefined
let u: undefined = undefined
let n: null = null
// Never(永远不会返回)
function error(message: string): never {
throw new Error(message)
}
// Unknown(比 any 更安全)
let notSure: unknown = 4
notSure = "maybe a string"
// notSure.toFixed() // ❌ 错误:必须先进行类型检查
3.2 类型推断
// TypeScript 会自动推断类型
let message = "Hello" // 推断为 string
let count = 10 // 推断为 number
let isActive = true // 推断为 boolean
// 数组类型推断
let arr = [1, 2, 3] // 推断为 number[]
四、接口和类型别名
4.1 接口(Interface)
// 定义接口
interface User {
id: number
name: string
email?: string // 可选属性
readonly createdAt: Date // 只读属性
}
// 使用接口
const user: User = {
id: 1,
name: "张三",
createdAt: new Date()
}
// user.createdAt = new Date() // ❌ 错误:只读属性不能修改
// 函数类型接口
interface SearchFunc {
(source: string, subString: string): boolean
}
const mySearch: SearchFunc = function(src, sub) {
return src.includes(sub)
}
// 可索引类型
interface StringArray {
[index: number]: string
}
const arr: StringArray = ["a", "b", "c"]
4.2 类型别名(Type Alias)
// 类型别名
type Point = {
x: number
y: number
}
type ID = number | string
type Callback = (data: string) => void
// 使用
const point: Point = { x: 10, y: 20 }
const userId: ID = 123
4.3 接口 vs 类型别名
// 接口可以扩展
interface Animal {
name: string
}
interface Dog extends Animal {
breed: string
}
// 类型别名使用交叉类型
type AnimalType = {
name: string
}
type DogType = AnimalType & {
breed: string
}
// 接口可以重复声明(合并)
interface Window {
title: string
}
interface Window {
width: number
}
// 最终 Window 接口包含 title 和 width
五、函数
5.1 函数类型注解
// 函数声明
function add(x: number, y: number): number {
return x + y
}
// 函数表达式
const multiply = function(x: number, y: number): number {
return x * y
}
// 箭头函数
const divide = (x: number, y: number): number => x / y
// 可选参数
function buildName(firstName: string, lastName?: string): string {
return lastName ? `${firstName} ${lastName}` : firstName
}
// 默认参数
function greet(name: string = "Guest"): string {
return `Hello, ${name}!`
}
// 剩余参数
function sum(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0)
}
// 函数重载
function getData(id: number): string
function getData(name: string): string[]
function getData(value: number | string): string | string[] {
if (typeof value === "number") {
return `Data for ID: ${value}`
} else {
return [`Data for ${value}`, "More data"]
}
}
六、类与面向对象
6.1 基本类
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}`
}
}
// 使用
const person = new Person("张三", 25)
console.log(person.greet())
6.2 访问修饰符
class BankAccount {
// 公共属性(默认)
public accountNumber: string
// 私有属性(只能在类内部访问)
private balance: number
// 受保护属性(只能在类和子类中访问)
protected owner: string
constructor(accountNumber: string, balance: number, owner: string) {
this.accountNumber = accountNumber
this.balance = balance
this.owner = owner
}
// 公共方法
public deposit(amount: number): void {
if (amount > 0) {
this.balance += amount
}
}
public getBalance(): number {
return this.balance
}
}
// 简写语法(TypeScript 特有)
class User {
constructor(
public id: number,
private name: string,
protected email: string
) {}
}
6.3 继承
class Animal {
constructor(public name: string) {}
move(distance: number = 0): void {
console.log(`${this.name} moved ${distance}m.`)
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name) // 调用父类构造函数
}
bark(): void {
console.log("Woof! Woof!")
}
// 重写父类方法
move(distance: number = 5): void {
console.log(`${this.name} runs...`)
super.move(distance)
}
}
const dog = new Dog("Buddy", "Golden Retriever")
dog.bark()
dog.move(10)
6.4 抽象类
abstract class Shape {
constructor(public color: string) {}
// 抽象方法(必须在子类中实现)
abstract getArea(): number
// 具体方法
getDescription(): string {
return `This is a ${this.color} shape`
}
}
class Circle extends Shape {
constructor(color: string, public radius: number) {
super(color)
}
getArea(): number {
return Math.PI * this.radius ** 2
}
}
// const shape = new Shape("red") // ❌ 错误:不能实例化抽象类
const circle = new Circle("red", 5)
console.log(circle.getArea())
6.5 接口实现
interface Flyable {
fly(): void
}
interface Swimmable {
swim(): void
}
class Duck implements Flyable, Swimmable {
fly(): void {
console.log("Duck is flying")
}
swim(): void {
console.log("Duck is swimming")
}
}
七、泛型
7.1 基本泛型
// 泛型函数
function identity<T>(arg: T): T {
return arg
}
// 使用
let output1 = identity<string>("Hello")
let output2 = identity(123) // 类型推断
// 泛型接口
interface GenericIdentityFn<T> {
(arg: T): T
}
// 泛型类
class GenericNumber<T> {
zeroValue: T
add: (x: T, y: T) => T
constructor(zeroValue: T, add: (x: T, y: T) => T) {
this.zeroValue = zeroValue
this.add = add
}
}
const myNumber = new GenericNumber<number>(0, (x, y) => x + y)
7.2 泛型约束
interface Lengthwise {
length: number
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length)
return arg
}
// loggingIdentity(3) // ❌ 错误:数字没有length属性
loggingIdentity("hello") // ✅
loggingIdentity([1, 2, 3]) // ✅
八、高级类型
8.1 联合类型和交叉类型
// 联合类型:可以是多种类型之一
type ID = number | string
// 交叉类型:同时具有多种类型的特性
interface Named {
name: string
}
interface Aged {
age: number
}
type Person = Named & Aged
const person: Person = {
name: "张三",
age: 25
}
8.2 类型守卫
// typeof 类型守卫
function padLeft(value: string, padding: string | number): string {
if (typeof padding === "number") {
return " ".repeat(padding) + value
}
return padding + value
}
// instanceof 类型守卫
class Bird {
fly() {
console.log("flying")
}
}
class Fish {
swim() {
console.log("swimming")
}
}
function move(pet: Bird | Fish) {
if (pet instanceof Bird) {
pet.fly()
} else {
pet.swim()
}
}
// 自定义类型守卫
interface Cat {
meow(): void
}
interface Dog {
bark(): void
}
function isDog(pet: Cat | Dog): pet is Dog {
return (pet as Dog).bark !== undefined
}
function makeSound(pet: Cat | Dog) {
if (isDog(pet)) {
pet.bark()
} else {
pet.meow()
}
}
九、模块系统
9.1 导出和导入
// math.ts - 导出
export const PI = 3.14159
export function add(x: number, y: number): number {
return x + y
}
export class Calculator {
multiply(x: number, y: number): number {
return x * y
}
}
// 默认导出
export default class AdvancedCalculator {
// ...
}
// main.ts - 导入
import { PI, add, Calculator } from './math'
import AdvancedCalculator from './math'
console.log(PI)
console.log(add(2, 3))
// 重命名导入
import { Calculator as Calc } from './math'
// 导入所有
import * as MathUtils from './math'
console.log(MathUtils.PI)
十、TypeScript 配置
10.1 tsconfig.json
{
"compilerOptions": {
// 基本配置
"target": "ES2020", // 编译目标版本
"module": "commonjs", // 模块系统
"lib": ["ES2020", "DOM"], // 包含的库文件
// 输出配置
"outDir": "./dist", // 输出目录
"rootDir": "./src", // 源代码目录
// 类型检查配置
"strict": true, // 启用所有严格类型检查
"noImplicitAny": true, // 禁止隐式 any
"strictNullChecks": true, // 严格的 null 检查
// 模块解析
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
},
// 其他
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
10.2 常用编译选项
# 编译整个项目
tsc
# 编译单个文件
tsc hello.ts
# 监听模式(自动重新编译)
tsc --watch
# 生成声明文件
tsc --declaration
# 指定配置文件
tsc --project tsconfig.prod.json
十一、实际应用示例
11.1 简单的 Todo 应用
// types/todo.ts
export interface Todo {
id: number
title: string
completed: boolean
createdAt: Date
}
export type FilterType = 'all' | 'active' | 'completed'
// services/todoService.ts
import { Todo } from '../types/todo'
class TodoService {
private todos: Todo[] = []
private nextId = 1
addTodo(title: string): Todo {
const todo: Todo = {
id: this.nextId++,
title,
completed: false,
createdAt: new Date()
}
this.todos.push(todo)
return todo
}
getTodos(filter: FilterType = 'all'): Todo[] {
switch (filter) {
case 'active':
return this.todos.filter(todo => !todo.completed)
case 'completed':
return this.todos.filter(todo => todo.completed)
default:
return [...this.todos]
}
}
toggleTodo(id: number): Todo | null {
const todo = this.todos.find(t => t.id === id)
if (todo) {
todo.completed = !todo.completed
return todo
}
return null
}
}
export const todoService = new TodoService()
// main.ts
import { todoService } from './services/todoService'
import type { FilterType } from './types/todo'
// 添加任务
todoService.addTodo("学习 TypeScript")
todoService.addTodo("完成项目")
// 切换任务状态
todoService.toggleTodo(1)
// 获取任务列表
const activeTodos = todoService.getTodos('active')
console.log(activeTodos)
11.2 API 请求封装
// types/api.ts
export interface ApiResponse<T> {
data: T
status: number
message: string
}
export interface User {
id: number
name: string
email: string
}
// utils/api.ts
import type { ApiResponse } from '../types/api'
class ApiClient {
private baseURL: string
constructor(baseURL: string) {
this.baseURL = baseURL
}
async get<T>(endpoint: string): Promise<ApiResponse<T>> {
const response = await fetch(`${this.baseURL}${endpoint}`)
return response.json()
}
async post<T>(endpoint: string, data: any): Promise<ApiResponse<T>> {
const response = await fetch(`${this.baseURL}${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
return response.json()
}
}
export const apiClient = new ApiClient('https://api.example.com')
// 使用
const fetchUsers = async () => {
try {
const response = await apiClient.get<User[]>('/users')
console.log(response.data)
} catch (error) {
console.error('获取用户失败:', error)
}
}
十二、常见问题解决
12.1 第三方库类型声明
# 安装类型声明文件
npm install --save-dev @types/lodash
npm install --save-dev @types/react
npm install --save-dev @types/node
12.2 缺少类型声明
// 声明模块
declare module 'untyped-module' {
export function someFunction(): void
}
// 全局声明
declare global {
interface Window {
myCustomProperty: string
}
}
十三、学习资源
13.1 官方资源
- TypeScript 官网
- TypeScript Playground
- TypeScript Handbook
13.2 推荐学习路径
- 基础:类型系统、接口、类
- 进阶:泛型、高级类型、装饰器
- 实战:配置项目、集成框架、工具链
13.3 练习建议
- 将现有 JavaScript 项目迁移到 TypeScript
- 使用 TypeScript 重写小型工具库
- 参与开源 TypeScript 项目
十四、总结
TypeScript 的核心价值:
- 类型安全:减少运行时错误
- 开发体验:更好的 IDE 支持
- 代码维护:清晰的类型注解
- 团队协作:明确的接口约定