通过完整可运行的代码示例,逐一深入讲解这 TypeScript 7 个 核心特性。
1. 接口(Interface)
作用
定义对象的结构契约,描述"一个对象应该长什么样",但不提供具体实现。用于类型检查、代码约定、团队协作。
详细示例
typescript
// ========== 基础接口 ==========
interface User {
id: number;
name: string;
email: string;
isActive?: boolean; // 可选属性
readonly createdAt: Date; // 只读属性,创建后不可修改
}
// 使用接口约束对象
const user: User = {
id: 1,
name: "张三",
email: "zhangsan@example.com",
createdAt: new Date()
};
// user.createdAt = new Date(); // ❌ 错误:readonly 属性不可修改
// ========== 接口描述函数形状 ==========
interface SearchFunc {
(source: string, subString: string): boolean;
}
const mySearch: SearchFunc = (src, sub) => {
return src.includes(sub);
};
// ========== 接口继承(扩展) ==========
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
bark(): void;
}
const myDog: Dog = {
name: "旺财",
breed: "金毛",
bark() {
console.log("汪汪!");
}
};
// ========== 接口实现类(与 class 结合) ==========
interface Printable {
print(): void;
getContent(): string;
}
class Document implements Printable {
constructor(private content: string) {}
print() {
console.log(`打印内容:${this.content}`);
}
getContent() {
return this.content;
}
}
const doc = new Document("合同文件");
doc.print(); // 打印内容:合同文件
// ========== 索引签名(动态属性) ==========
interface StringDictionary {
[key: string]: string;
}
const translations: StringDictionary = {
hello: "你好",
world: "世界"
};
实际应用场景
- API 响应类型定义:前后端约定数据结构
- 组件 Props 类型:React/Vue 组件入参约束
- 插件系统:定义插件必须实现的接口
2. 类与访问修饰符
作用
控制类成员的可见性,实现封装,防止外部随意修改内部状态。
详细示例
typescript
// ========== 三种访问修饰符 ==========
class BankAccount {
// public: 公开(默认),任何地方可访问
public accountNumber: string;
// private: 仅类内部可访问,实例和子类都不可访问
private balance: number;
// protected: 类内部和子类可访问,实例不可访问
protected ownerName: string;
constructor(accountNumber: string, ownerName: string, initialBalance: number) {
this.accountNumber = accountNumber;
this.ownerName = ownerName;
this.balance = initialBalance;
}
// public 方法
public deposit(amount: number): void {
if (amount <= 0) {
throw new Error("存款金额必须大于0");
}
this.balance += amount;
this.logTransaction("存款", amount);
}
public withdraw(amount: number): void {
if (amount > this.balance) {
throw new Error("余额不足");
}
this.balance -= amount;
this.logTransaction("取款", amount);
}
public getBalance(): number {
return this.balance;
}
// private 方法:内部辅助逻辑
private logTransaction(type: string, amount: number): void {
console.log(`[${new Date().toISOString()}] ${type}: ¥${amount}`);
}
}
// ========== 使用 ==========
const account = new BankAccount("622202123456", "张三", 1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
console.log(account.accountNumber); // ✅ 可以访问 public
// account.balance = 999999; // ❌ 错误:属性是 private
// account.ownerName; // ❌ 错误:属性是 protected
// ========== protected 在继承中的使用 ==========
class SavingsAccount extends BankAccount {
private interestRate: number;
constructor(accountNumber: string, ownerName: string, balance: number, rate: number) {
super(accountNumber, ownerName, balance);
this.interestRate = rate;
}
public applyInterest(): void {
// 子类可以访问 protected 的 ownerName
console.log(`为 ${this.ownerName} 计算利息`);
const interest = this.getBalance() * this.interestRate;
this.deposit(interest);
}
}
const savings = new SavingsAccount("622202999999", "李四", 10000, 0.03);
savings.applyInterest();
// 输出:为 李四 计算利息
参数属性简写(语法糖)
typescript
class Person {
// 直接在构造函数参数中声明属性,自动赋值
constructor(
public name: string,
private age: number,
protected id: string
) {}
}
const p = new Person("王五", 25, "ID001");
console.log(p.name); // 王五
3. 抽象类与实现
作用
- 抽象类 :不能被实例化,只能被继承,用于定义子类的通用模板
- 抽象方法:只有声明没有实现,强制子类必须实现
详细示例
typescript
// ========== 抽象类定义 ==========
abstract class Shape {
// 抽象属性(子类必须实现)
abstract name: string;
// 具体属性(子类继承即用)
color: string = "black";
// 抽象方法:只有签名,没有实现
abstract calculateArea(): number;
abstract calculatePerimeter(): number;
// 具体方法:所有子类共享的实现
describe(): string {
return `这是一个${this.color}色的${this.name},` +
`面积=${this.calculateArea()},` +
`周长=${this.calculatePerimeter()}`;
}
}
// ========== 具体实现类 ==========
class Rectangle extends Shape {
name = "矩形";
constructor(
public width: number,
public height: number,
color: string = "蓝色"
) {
super();
this.color = color;
}
calculateArea(): number {
return this.width * this.height;
}
calculatePerimeter(): number {
return 2 * (this.width + this.height);
}
}
class Circle extends Shape {
name = "圆形";
constructor(
public radius: number,
color: string = "红色"
) {
super();
this.color = color;
}
calculateArea(): number {
return Math.PI * this.radius ** 2;
}
calculatePerimeter(): number {
return 2 * Math.PI * this.radius;
}
}
// ========== 使用 ==========
// const shape = new Shape(); // ❌ 错误:无法创建抽象类的实例
const rect = new Rectangle(10, 5, "绿色");
console.log(rect.describe());
// 输出:这是一个绿色的矩形,面积=50,周长=30
const circle = new Circle(7);
console.log(circle.describe());
// 输出:这是一个红色的圆形,面积=153.9380...,周长=43.9822...
// ========== 多态使用 ==========
const shapes: Shape[] = [rect, circle];
shapes.forEach(s => console.log(s.describe()));
与接口的区别
| 抽象类 | 接口 | |
|---|---|---|
| 实现 | 可包含具体方法和属性 | 只能声明,不能实现 |
| 继承 | 单继承(一个类只能 extends 一个) | 多实现(一个类可 implements 多个) |
| 实例化 | 不能 | 不能 |
| 用途 | 代码复用 + 模板约束 | 纯契约定义 |
4. 模块与命名空间
作用
- 模块(Module) :基于文件的组织方式,每个文件是一个模块,通过
import/export管理依赖 - 命名空间(Namespace):用于将相关代码组织到同一个命名空间下,避免全局污染
详细示例
模块系统(现代推荐方式)
typescript
// ========== math-utils.ts ==========
// 命名导出
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
// 默认导出
export default class Calculator {
private history: string[] = [];
execute(operation: string, a: number, b: number): number {
let result: number;
switch(operation) {
case 'add': result = add(a, b); break;
case 'multiply': result = multiply(a, b); break;
default: throw new Error("未知操作");
}
this.history.push(`${operation}(${a}, ${b}) = ${result}`);
return result;
}
getHistory(): string[] {
return [...this.history];
}
}
// 类型导出
export interface MathConfig {
precision: number;
allowNegative: boolean;
}
typescript
// ========== main.ts ==========
// 默认导入
import Calculator from './math-utils';
// 命名导入
import { add, multiply, MathConfig } from './math-utils';
// 全部导入为命名空间
import * as MathUtils from './math-utils';
// 使用
const calc = new Calculator();
console.log(calc.execute('add', 5, 3)); // 8
console.log(add(10, 20)); // 30
const config: MathConfig = {
precision: 2,
allowNegative: false
};
命名空间(适合大型库内部组织)
typescript
// ========== 命名空间定义 ==========
namespace Validation {
export interface StringValidator {
isValid(s: string): boolean;
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export class EmailValidator implements StringValidator {
isValid(s: string): boolean {
return emailRegex.test(s);
}
}
export class PhoneValidator implements StringValidator {
isValid(s: string): boolean {
return /^1[3-9]\d{9}$/.test(s);
}
}
// 未 export 的只能在命名空间内部使用
function logValidation(result: boolean): void {
console.log(`验证结果:${result ? '通过' : '失败'}`);
}
}
// ========== 使用 ==========
const emailVal = new Validation.EmailValidator();
console.log(emailVal.isValid("test@example.com")); // true
const phoneVal = new Validation.PhoneValidator();
console.log(phoneVal.isValid("13800138000")); // true
// 嵌套命名空间
namespace App {
export namespace Utils {
export function formatDate(d: Date): string {
return d.toLocaleDateString('zh-CN');
}
}
}
console.log(App.Utils.formatDate(new Date()));
现代项目推荐 :优先使用模块(ES Module),命名空间主要用于遗留代码或需要打包成单个全局变量的库。
5. 装饰器(Decorators)
作用
装饰器是一种特殊类型的声明 ,可以附加到类、方法、属性或参数上,用于修改或增强它们的行为。广泛用于 NestJS、Angular、TypeORM 等框架。
详细示例
需要先开启装饰器支持(见第 7 节配置)。
typescript
// ========== 类装饰器 ==========
function LogClass(target: Function) {
console.log(`类 ${target.name} 被创建了`);
}
@LogClass
class UserService {
constructor() {
console.log("UserService 实例化");
}
}
// 输出:类 UserService 被创建了
// ========== 方法装饰器 ==========
function MeasureTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
const start = performance.now();
const result = originalMethod.apply(this, args);
const end = performance.now();
console.log(`${propertyKey} 执行耗时: ${(end - start).toFixed(2)}ms`);
return result;
};
return descriptor;
}
class DataProcessor {
@MeasureTime
heavyComputation(n: number): number {
let sum = 0;
for (let i = 0; i < n; i++) {
sum += Math.sqrt(i);
}
return sum;
}
}
const processor = new DataProcessor();
processor.heavyComputation(1000000);
// 输出:heavyComputation 执行耗时: 12.34ms
// ========== 属性装饰器 ==========
function Required(target: any, propertyKey: string) {
// 注册验证规则
let validators = target.constructor.prototype._validators || [];
validators.push({ field: propertyKey, type: 'required' });
target.constructor.prototype._validators = validators;
}
function Validate(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
const validators = this._validators || [];
for (const v of validators) {
if (v.type === 'required' && !this[v.field]) {
throw new Error(`验证失败:${v.field} 不能为空`);
}
}
return original.apply(this, args);
};
}
class User {
@Required
name: string = "";
@Required
email: string = "";
@Validate
save() {
console.log(`保存用户:${this.name}, ${this.email}`);
}
}
const user = new User();
// user.save(); // ❌ 抛出错误:验证失败:name 不能为空
user.name = "张三";
user.email = "zs@example.com";
user.save(); // ✅ 保存用户:张三, zs@example.com
// ========== 参数装饰器(NestJS 风格) ==========
function Body() {
return function (target: any, propertyKey: string, parameterIndex: number) {
// 标记参数需要从请求体中获取
const metadata = Reflect.getMetadata('design:paramtypes', target, propertyKey) || [];
console.log(`方法 ${propertyKey} 的第 ${parameterIndex} 个参数标记为 Body`);
};
}
class UserController {
createUser(@Body() userData: any) {
console.log("创建用户:", userData);
}
}
装饰器工厂(带参数的装饰器)
typescript
function Cacheable(ttlSeconds: number) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const cache = new Map();
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log("命中缓存");
return cache.get(key);
}
const result = original.apply(this, args);
cache.set(key, result);
setTimeout(() => cache.delete(key), ttlSeconds * 1000);
return result;
};
};
}
class ApiService {
@Cacheable(60) // 缓存 60 秒
fetchUser(id: number) {
console.log(`发起网络请求获取用户 ${id}`);
return { id, name: `用户${id}` };
}
}
const api = new ApiService();
api.fetchUser(1); // 发起网络请求
api.fetchUser(1); // 命中缓存
6. 泛型编程
作用
编写类型安全的通用代码,让函数/类/接口可以处理多种类型,同时保持类型推断和检查。
详细示例
typescript
// ========== 泛型函数 ==========
// T 是类型参数,调用时传入或自动推断
function identity<T>(arg: T): T {
return arg;
}
const num = identity<number>(42); // num 类型是 number
const str = identity("hello"); // 自动推断为 string
// ========== 泛型约束 ==========
interface HasLength {
length: number;
}
// T 必须具有 length 属性
function logLength<T extends HasLength>(arg: T): T {
console.log(`长度:${arg.length}`);
return arg;
}
logLength("hello"); // ✅ 长度:5
logLength([1, 2, 3]); // ✅ 长度:3
// logLength(123); // ❌ 错误:number 没有 length
// ========== 泛型接口 ==========
interface ApiResponse<T> {
code: number;
message: string;
data: T;
}
// 复用同一接口结构,数据类型不同
const userResponse: ApiResponse<{ id: number; name: string }> = {
code: 200,
message: "成功",
data: { id: 1, name: "张三" }
};
const listResponse: ApiResponse<string[]> = {
code: 200,
message: "成功",
data: ["a", "b", "c"]
};
// ========== 泛型类 ==========
class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
peek(): T | undefined {
return this.items[this.items.length - 1];
}
isEmpty(): boolean {
return this.items.length === 0;
}
}
// 数字栈
const numberStack = new Stack<number>();
numberStack.push(10);
numberStack.push(20);
// numberStack.push("hello"); // ❌ 错误
// 字符串栈
const stringStack = new Stack<string>();
stringStack.push("first");
stringStack.push("second");
// ========== 泛型工具类型 ==========
interface Person {
name: string;
age: number;
email: string;
}
// Partial<T>:所有属性变为可选
const partialPerson: Partial<Person> = { name: "张三" };
// Pick<T, K>:从 T 中选取部分属性
type PersonName = Pick<Person, 'name' | 'age'>; // { name: string; age: number }
// Omit<T, K>:从 T 中排除部分属性
type PersonWithoutEmail = Omit<Person, 'email'>; // { name: string; age: number }
// Record<K, T>:创建键值对类型
const scoreMap: Record<string, number> = {
"张三": 90,
"李四": 85
};
// ========== 高级:条件类型与映射类型 ==========
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<123>; // false
// 将对象所有属性变为只读
type ReadonlyPerson = Readonly<Person>;
// 等价于:{ readonly name: string; readonly age: number; readonly email: string; }
7. 配置与工具链
作用
tsconfig.json 是 TypeScript 项目的核心配置文件,控制编译行为、类型检查严格程度、输出目标等。
完整配置示例与详解
json
{
// ========== 编译选项 ==========
"compilerOptions": {
// --- 目标与模块 ---
"target": "ES2020", // 编译目标 JS 版本:ES3/ES5/ES6/ES2017/ES2020/ESNext
"module": "ESNext", // 模块系统:CommonJS/AMD/UMD/System/ESNext
"lib": ["ES2020", "DOM"], // 包含的类型定义库
// --- 输出配置 ---
"outDir": "./dist", // 编译输出目录
"rootDir": "./src", // 源码根目录
"declaration": true, // 生成 .d.ts 类型声明文件(开发库时必备)
"declarationDir": "./types", // 声明文件输出目录
"sourceMap": true, // 生成 .map 文件,用于调试
"removeComments": true, // 编译时移除注释
// --- 严格类型检查(强烈推荐开启)---
"strict": true, // 启用所有严格类型检查选项
"noImplicitAny": true, // 禁止隐式 any(表达式/声明没有类型时)
"strictNullChecks": true, // null/undefined 不能赋值给其他类型
"strictFunctionTypes": true, // 函数参数双向协变检查
"noImplicitReturns": true, // 函数必须有显式返回值
"noFallthroughCasesInSwitch": true, // switch 禁止 case 穿透
// --- 代码质量 ---
"noUnusedLocals": true, // 报错未使用的局部变量
"noUnusedParameters": true, // 报错未使用的参数(可用 _ 前缀忽略)
"noImplicitOverride": true, // 重写父类方法必须加 override 关键字
// --- 模块解析 ---
"moduleResolution": "node", // 模块解析策略:node/classic
"baseUrl": ".", // 基础路径,用于路径别名
"paths": { // 路径别名映射
"@/*": ["src/*"],
"@utils/*": ["src/utils/*"]
},
"esModuleInterop": true, // 兼容 CommonJS 模块的默认导入
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true, // 允许导入 JSON 文件
// --- JSX(React 项目)---
"jsx": "react-jsx", // react-jsx/react/preserve
"jsxImportSource": "react",
// --- 装饰器 ---
"experimentalDecorators": true, // 启用装饰器
"emitDecoratorMetadata": true, // 为装饰器生成元数据(TypeORM 等需要)
// --- 其他 ---
"skipLibCheck": true, // 跳过 node_modules 中声明文件的类型检查(加速编译)
"forceConsistentCasingInFileNames": true // 强制文件名大小写一致
},
// ========== 包含/排除文件 ==========
"include": [
"src/**/*", // 编译 src 目录下所有文件
"types/**/*"
],
"exclude": [
"node_modules",
"dist",
"**/*.test.ts", // 排除测试文件
"**/*.spec.ts"
],
// ========== 项目引用(大型项目分模块编译)==========
"references": [
{ "path": "./packages/shared" },
{ "path": "./packages/core" }
]
}
实际使用方式
bash
# 1. 初始化项目
npm init -y
npm install typescript --save-dev
npx tsc --init # 生成 tsconfig.json
# 2. 开发时实时编译(监视模式)
npx tsc --watch
# 3. 生产构建
npx tsc # 一次性编译
# 4. 配合构建工具(推荐)
# Vite(零配置支持 TS)
npm create vite@latest my-app -- --template react-ts
# Webpack
npm install ts-loader --save-dev
# esbuild / swc(超高速编译)
npm install esbuild --save-dev
路径别名实战
typescript
// tsconfig.json 中配置
// "paths": { "@/*": ["src/*"] }
// 实际代码中使用
import { formatDate } from '@/utils/date';
import { User } from '@/types/user';
// 替代冗长的相对路径:../../../utils/date
严格模式渐进开启策略
json
// 新项目:直接 strict: true
// 老项目迁移:逐步开启
{
"compilerOptions": {
"strict": false,
"noImplicitAny": true, // 第一步:先解决隐式 any
"strictNullChecks": false, // 第二步:后续逐步开启
"strictFunctionTypes": false
}
}
总结速查表
| 特性 | 核心作用 | 典型使用场景 |
|---|---|---|
| Interface | 定义对象结构契约 | API 类型、组件 Props、类实现规范 |
| 访问修饰符 | 控制可见性,实现封装 | 保护内部状态,防止非法修改 |
| 抽象类 | 定义通用模板,强制子类实现 | 框架基类、插件系统、多态处理 |
| 模块/命名空间 | 代码组织与隔离 | 项目模块化、避免全局污染 |
| 装饰器 | 元编程,增强类/方法/属性 | AOP 日志、权限校验、缓存、依赖注入 |
| 泛型 | 类型安全的通用代码 | 工具函数、数据结构、API 封装 |
| tsconfig | 控制编译与类型检查行为 | 项目初始化、严格度配置、路径别名 |