TypeScript知识点梳理
注:纯手打,如有错误欢迎评论区交流!
转载请注明出处:https://blog.csdn.net/testleaf/article/details/148275110
编写此文是为了更好地学习前端知识,如果损害了有关人的利益,请联系删除!
本文章将不定时更新,敬请期待!!!
欢迎点赞、收藏、转发、关注,多谢!!!
目录
- 一、TypeScript和JavaScript对比
- 二、编译TypeScript
- 1、基础编译流程
- 2、关键编译配置项
- 3、编译模式
- 4、与构建工具集成【如Webpack】
- 5、Vite/Rollup
- 6、总结
- 三、类型声明
- 1、基础类型声明
- 2、对象与接口
- 3、函数类型声明
- 4、高级类型
- 5、类型断言与守卫
- 6、模块与全局类型
- 7、最佳实践
- 四、类型总览
- 1、原始类型(Primitive Types)
- 2、对象类型(Object Types)
- 3、特殊类型
- 4、高级类型
- 5、泛型(Generics)
- 6、条件类型(Conditional Types)
- 7、类型操作
- 8、类型声明合并
- 9、最佳实践
- 五、类
- 1、基础类定义
- 2、访问修饰符
- 3、参数属性(简写语法)
- 4、Getter/Setter
- 5、静态成员
- 6、抽象类
- 7、类与接口
- 8、高级特性
- 9、最佳实践
- 六、类型声明文件
- 1、声明文件的作用
- 2、声明文件的分类
- 3、核心语法
- 4、声明文件的存放位置
- 5、自动生成声明文件
- 6、常见场景示例
- 7、最佳实践
- 8、调试技巧
- 七、装饰器
- 1、启用装饰器
- 2、装饰器类型
- 3、装饰器工厂
- 4、装饰器执行顺序
- 5、实际应用场景
- 6、注意事项
一、TypeScript和JavaScript对比
- 选择 TypeScript:
- 适合中大型项目、长期维护的代码库或需要强类型保障的场景。
- 示例:React/Angular 应用、Node.js 后端服务。
- 选择 JavaScript:
- 适合快速原型开发、小型脚本或已有成熟 JS 代码库。
- 示例:简单的网页交互、一次性脚本。
- 关键差异一句话:
- TypeScript = JavaScript + 静态类型系统 + 开发时工具增强,牺牲少量灵活性换取长期可维护性。
二、编译TypeScript
1、基础编译流程
步骤 1:安装 TypeScript 编译器
npm install -g typescript # 全局安装
# 或
npm install --save-dev typescript # 项目内安装
步骤 2:创建 tsconfig.json
运行以下命令生成默认配置:
tsc --init
或手动创建配置文件(示例):
{"compilerOptions": {"target": "ES6", // 编译目标 JS 版本"module": "CommonJS", // 模块系统"outDir": "./dist", // 输出目录"strict": true // 启用严格类型检查},"include": ["src/**/*"] // 需编译的文件路径
}
步骤 3:执行编译
tsc # 编译所有文件(根据 tsconfig.json)
tsc src/index.ts # 编译单个文件(忽略 tsconfig.json)
2、关键编译配置项
配置项 | 作用 | 常用值 |
---|---|---|
target | 指定输出的 JS 版本 | ES5, ES6, ES2022 |
module | 模块化方案 | CommonJS, ES6, AMD |
outDir | 编译后的 JS 文件输出目录 | “./dist” |
strict | 启用所有严格类型检查(推荐开启) | true/false |
noImplicitAny | 禁止隐式 any 类型(需显式标注) | true |
sourceMap | 生成 .map 文件以支持调试原始 TS 代码 | true |
esModuleInterop | 改善 CommonJS/ES Module 的兼容性 | true |
3、编译模式
实时监听模式
tsc --watch # 自动重新编译修改的文件
增量编译
tsc --incremental # 仅编译变更部分(加快后续编译速度)
4、与构建工具集成【如Webpack】
安装 ts-loader:
npm install --save-dev ts-loader
修改 webpack.config.js:
module.exports = {module: {rules: [{test: /\.tsx?$/,use: 'ts-loader',exclude: /node_modules/,},],},resolve: {extensions: ['.tsx', '.ts', '.js'],},
};
5、Vite/Rollup
直接支持 TypeScript,无需额外配置(需确保 tsconfig.json 存在)。
6、总结
- 核心工具:
tsc
(TypeScript 编译器) +tsconfig.json
。 - 推荐实践:开启
strict
严格模式,配合--watch
或构建工具实现自动化。 - 扩展能力:通过 Babel 支持最新语法,或与 Webpack/Vite 等工具链集成。
三、类型声明
1、基础类型声明
原始类型
let name: string = "Alice";
let age: number = 25;
let isActive: boolean = true;
let nothing: null = null;
let notDefined: undefined = undefined;
let bigInt: bigint = 100n;
let symbolKey: symbol = Symbol("id");
数组与元组
let numbers: number[] = [1, 2, 3]; // 数字数组
let mixed: (string | number)[] = ["a", 1]; // 联合类型数组let tuple: [string, number] = ["Alice", 25]; // 固定长度和类型的元组
2、对象与接口
接口(Interface)
定义对象结构的首选方式:
interface User {id: number;name: string;email?: string; // 可选属性readonly createdAt: Date; // 只读属性
}const user: User = {id: 1,name: "Alice",createdAt: new Date(),
};
类型别名(Type Alias)
适用于复杂类型或联合类型:
type Point = {x: number;y: number;
};type ID = string | number; // 联合类型
区别:Interface vs Type
特性 | Interface | Type Alias |
---|---|---|
扩展性 | ✅ 可通过 extends 继承 | ✅ 使用交叉类型(& ) |
合并声明 | ✅ 同名接口自动合并 | ❌ 不允许重复声明 |
适用场景 | 对象结构、类实现 | 联合类型、元组、复杂类型表达式 |
3、函数类型声明
函数参数与返回值
// 方式1:直接标注
function add(a: number, b: number): number {return a + b;
}// 方式2:类型别名
type AddFn = (a: number, b: number) => number;
const add2: AddFn = (a, b) => a + b;
可选参数与默认值
function greet(name: string, prefix: string = "Hello"): string {return `${prefix}, ${name}!`;
}
剩余参数
function sum(...numbers: number[]): number {return numbers.reduce((acc, n) => acc + n, 0);
}
4、高级类型
联合类型(Union Types)
type Status = "success" | "error" | "pending";
let currentStatus: Status = "success";
交叉类型(Intersection Types)
type Admin = { role: "admin" };
type User = { name: string };
type AdminUser = Admin & User; // { role: "admin", name: string }
泛型(Generics)
function identity<T>(value: T): T {return value;
}
identity<string>("Alice"); // 显式指定类型
identity(42); // 自动推断为 number
工具类型(Utility Types)
interface Todo {title: string;completed: boolean;
}type PartialTodo = Partial<Todo>; // 所有属性变为可选
type ReadonlyTodo = Readonly<Todo>; // 所有属性变为只读
type TodoPreview = Pick<Todo, "title">; // 仅保留指定属性
5、类型断言与守卫
类型断言(Type Assertion)
明确告诉编译器值的类型:
let input: unknown = "hello";
let length: number = (input as string).length; // 方式1
let length2: number = (<string>input).length; // 方式2(JSX 中不可用)
类型守卫(Type Guards)
运行时检查类型:
function isString(value: unknown): value is string {return typeof value === "string";
}if (isString(input)) {console.log(input.toUpperCase()); // 此处 input 被识别为 string
}
6、模块与全局类型
模块内类型导出
// types.ts
export interface Product {id: number;name: string;
}// app.ts
import { Product } from "./types";
全局类型声明
// global.d.ts
declare type GlobalConfig = {env: "dev" | "prod";
};// 任何文件可直接使用 GlobalConfig
const config: GlobalConfig = { env: "dev" };
7、最佳实践
- 始终开启 strict 模式。
- 优先用 interface 定义对象,用 type 处理联合/交叉类型。
- 泛型提升代码复用性,工具类型减少重复定义。
四、类型总览
1、原始类型(Primitive Types)
let str: string = "Hello";
let num: number = 42;
let bool: boolean = true;
let nul: null = null;
let undef: undefined = undefined;
let big: bigint = 9007199254740991n;
let sym: symbol = Symbol("key");
特点:对应 JavaScript 的 7 种原始数据类型。
2、对象类型(Object Types)
数组
let arr1: number[] = [1, 2, 3];
let arr2: Array<string> = ["a", "b"]; // 泛型语法
let arr3: (number | string)[] = [1, "a"]; // 联合类型数组
元组(Tuple)
let tuple: [string, number] = ["Alice", 25]; // 固定长度和类型
tuple.push("extra"); // 允许但不推荐(破坏元组约束)
对象字面量
let obj: { name: string; age?: number; // 可选属性readonly id: number; // 只读属性
} = { name: "Alice", id: 1 };
3、特殊类型
类型 | 说明 | 示例 |
---|---|---|
any | 禁用类型检查 | let val: any = "anything"; |
unknown | 类型安全的 any,需类型断言或守卫后才能使用 | let u: unknown = fetchData(); |
void | 表示无返回值(常见于函数) | function log(): void { ... } |
never | 表示永不返回(如抛出错误或死循环) | function fail(): never { throw Error(); } |
enum | 枚举类型 | enum Color { Red, Green } |
4、高级类型
联合类型(Union)
type Status = "success" | "error" | "pending";
let status: Status = "success";function padLeft(value: string, padding: string | number) { ... }
交叉类型(Intersection)
type Admin = { permissions: string[] };
type User = { name: string };
type AdminUser = Admin & User; // { permissions: string[], name: string }
索引类型
interface StringArray {[index: number]: string; // 数字索引签名
}
const arr: StringArray = ["a", "b"];
映射类型(Mapped Types)
type Readonly<T> = { readonly [P in keyof T]: T[P] };
type Optional<T> = { [P in keyof T]?: T[P] };
5、泛型(Generics)
基础泛型
function identity<T>(arg: T): T {return arg;
}
identity<string>("text"); // 显式指定类型
identity(42); // 自动推断为 number
泛型约束
interface Lengthwise {length: number;
}function logLength<T extends Lengthwise>(arg: T): void {console.log(arg.length);
}
泛型工具类
type Partial<T> = { [P in keyof T]?: T[P] }; // 所有属性可选
type Pick<T, K extends keyof T> = { [P in K]: T[P] }; // 选取部分属性
6、条件类型(Conditional Types)
type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<number>; // false
内置条件类型
type Exclude<T, U> = T extends U ? never : T; // 从 T 中排除 U
type Extract<T, U> = T extends U ? T : never; // 从 T 中提取 U
7、类型操作
类型推断(infer)
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type FnReturn = ReturnType<() => number>; // number
模板字面量类型
type EventName = `on${"Click" | "Hover"}`; // "onClick" | "onHover"
8、类型声明合并
接口合并
interface Box { width: number; }
interface Box { height: number; }
// 合并为 { width: number; height: number; }
命名空间合并
namespace Network {export function request() {}
}
namespace Network {export function response() {}
}
// 合并后包含 request 和 response 方法
9、最佳实践
- 优先使用 interface 定义对象结构,用 type 处理复杂类型操作。
- 避免 any,用 unknown + 类型守卫保证类型安全。
- 善用工具类型(如 Partial, Pick)减少重复代码。
- 泛型提升代码复用性,但避免过度抽象。
- 开启 strict 模式 最大化类型检查收益。
五、类
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 alice = new Person("Alice", 25);
console.log(alice.greet()); // "Hello, I'm Alice"
2、访问修饰符
修饰符 | 作用 | 示例 |
---|---|---|
public | 默认值,任意位置可访问 | public name: string; |
private | 仅类内部可访问 | private secret: string; |
protected | 类内部及子类可访问 | protected id: number; |
readonly | 只读属性(需初始化) | readonly id: number; |
class Employee extends Person {private salary: number;constructor(name: string, age: number, salary: number) {super(name, age);this.salary = salary;}getSalary(): number {return this.salary; // 允许访问 private 属性}
}const emp = new Employee("Bob", 30, 5000);
console.log(emp.name); // ✅ 允许(public)
console.log(emp.salary); // ❌ 错误(private)
3、参数属性(简写语法)
将构造函数参数直接定义为属性:
class Point {constructor(public x: number,public y: number,private readonly id: string) {}
}const p = new Point(10, 20, "p1");
console.log(p.x); // 10(自动成为 public 属性)
4、Getter/Setter
class Temperature {private _celsius: number = 0;get celsius(): number {return this._celsius;}set celsius(value: number) {if (value < -273.15) throw new Error("Too cold!");this._celsius = value;}get fahrenheit(): number {return this._celsius * 1.8 + 32;}
}const temp = new Temperature();
temp.celsius = 25; // 调用 setter
console.log(temp.fahrenheit); // 77(调用 getter)
5、静态成员
class Logger {static instance: Logger;private logs: string[] = [];private constructor() {} // 私有构造函数(单例模式)static getInstance(): Logger {if (!Logger.instance) {Logger.instance = new Logger();}return Logger.instance;}log(message: string): void {this.logs.push(message);console.log(message);}
}// 使用单例
Logger.getInstance().log("System started");
6、抽象类
abstract class Animal {abstract makeSound(): void; // 抽象方法(需子类实现)move(): void {console.log("Moving...");}
}class Dog extends Animal {makeSound(): void {console.log("Woof!");}
}const dog = new Dog();
dog.makeSound(); // "Woof!"
7、类与接口
实现接口
interface ClockInterface {currentTime: Date;setTime(d: Date): void;
}class Clock implements ClockInterface {currentTime: Date = new Date();setTime(d: Date): void {this.currentTime = d;}
}
类类型接口
interface ClockConstructor {new (hour: number, minute: number): ClockInstance;
}interface ClockInstance {tick(): void;
}function createClock(ctor: ClockConstructor,h: number,m: number
): ClockInstance {return new ctor(h, m);
}class DigitalClock implements ClockInstance {constructor(h: number, m: number) {}tick() {console.log("beep beep");}
}const digital = createClock(DigitalClock, 12, 30);
8、高级特性
装饰器(实验性)
function log(target: any, key: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`Calling ${key} with`, args);return originalMethod.apply(this, args);// 或者:return originalMethod.call(this, ...args);};
}class Calculator {@logadd(a: number, b: number): number {return a + b;}
}
泛型类
class Box<T> {private value: T;constructor(value: T) {this.value = value;}getValue(): T {return this.value;}
}const stringBox = new Box<string>("Hello");
const numberBox = new Box<number>(42);
类与类型的关系
class Car {model: string = "";
}// 类本身作为类型
const car1: Car = new Car();// 类类型包含静态部分和实例部分
typeof Car; // 构造函数类型
Car.prototype; // 实例原型
9、最佳实践
- 优先使用 private 封装内部状态,通过方法暴露必要操作。
- 避免过度继承,组合优于继承(使用接口定义行为)。
- 抽象类适合定义通用模板,接口适合定义契约。
- 开启 strictPropertyInitialization 确保属性初始化安全。
- 示例项目结构建议:
// interfaces/vehicle.ts
export interface Vehicle {start(): void;stop(): void;
}// classes/Car.ts
import { Vehicle } from "../interfaces/vehicle";export class Car implements Vehicle {start() { /* ... */ }stop() { /* ... */ }
}
六、类型声明文件
在 TypeScript 中,类型声明文件(.d.ts 文件) 用于描述 JavaScript 库或模块的类型信息,使 TypeScript 能对非 TS 代码进行类型检查。
1、声明文件的作用
- 为 JS 库提供类型支持(如 jQuery、Lodash)
- 描述全局变量/模块的类型
- 扩展已有类型定义
- 避免在业务代码中混入类型声明
2、声明文件的分类
全局类型声明(无导入导出)
// global.d.ts
declare const __VERSION__: string; // 全局变量
declare interface Window {myLib: { version: string }; // 扩展全局接口
}declare module "*.png" { // 模块声明const path: string;export default path;
}
模块类型声明(含导入导出)
// types/module.d.ts
declare module "my-library" {export function doSomething(config: { timeout: number }): void;
}
第三方库类型(@types/xxx)
通过 DefinitelyTyped 安装:
npm install --save-dev @types/lodash
3、核心语法
变量/函数声明
declare const PI: number;
declare function greet(name: string): void;
类型/接口声明
declare type UserID = string | number;
declare interface User {id: UserID;name: string;
}
命名空间(模拟旧版模块)
declare namespace MyLib {export const version: string;export function parse(text: string): object;
}
扩展已有声明
// 扩展 Express 的 Request 类型
declare namespace Express {interface Request {user?: { id: string };}
}
4、声明文件的存放位置
场景 | 推荐路径 | 说明 |
---|---|---|
全局类型 | ./types/global.d.ts | 自动被 TS 识别(需在 tsconfig.json 的 "include" 中包含该目录) |
模块补充类型 | ./types/module-name.d.ts | 通过 declare module 扩展模块类型(如为第三方库添加类型声明) |
第三方库类型 | node_modules/@types/ | 自动从 @types/ 加载(通过 npm install @types/包名 安装) |
配置 tsconfig.json:
{"compilerOptions": {"typeRoots": ["./types", "./node_modules/@types"]},"include": ["src/**/*", "types/**/*"]
}
5、自动生成声明文件
为 TS 项目生成 .d.ts
在 tsconfig.json 中配置:
{"compilerOptions": {"declaration": true,"outDir": "dist/types"}
}
编译后将生成对应的声明文件(如 dist/types/index.d.ts)。
从 JS 代码生成(JSDoc 注释)
通过 allowJs 和 declaration 选项:
{"compilerOptions": {"allowJs": true,"declaration": true}
}
6、常见场景示例
为 Legacy JS 库添加类型
// types/old-lib.d.ts
declare module "old-lib" {export function calculate(a: number, b: number): number;export const DEFAULT_TIMEOUT: number;
}
扩展 Vue 组件选项
// types/vue.d.ts
import Vue from "vue";
declare module "vue/types/options" {interface ComponentOptions<V extends Vue> {customOption?: string;}
}
定义 CSS Modules 类型
// types/css-modules.d.ts
declare module "*.module.css" {const classes: { [key: string]: string };export default classes;
}
7、最佳实践
- 优先使用
@types/
包:- 在 DefinitelyTyped 已存在类型定义时直接安装。
- 最小化全局声明:
- 尽量通过模块声明(declare module)而非全局变量。
- 类型合并优于覆盖:
- 使用 interface 扩展而非重新声明。
- 保持与源码同步:
- 当修改 JS 代码时,需同步更新声明文件。
- 验证声明文件:
- 通过
tsc --noEmit
检查类型是否正确定义。
- 通过
8、调试技巧
检查类型定义
// test.ts
import { someFunction } from "your-library";
someFunction("test"); // 触发类型检查
快速定位问题
- 使用 VS Code 的 Go to Definition 跳转到声明文件
- 通过
tsc --traceResolution
查看类型解析过程
七、装饰器
1、启用装饰器
在 tsconfig.json 中启用实验性支持:
{"compilerOptions": {"experimentalDecorators": true,"emitDecoratorMetadata": true // 可选:生成反射元数据}
}
2、装饰器类型
类装饰器
应用于类的构造函数,用于修改或替换类定义:
function LogClass(target: Function) {console.log(`Class ${target.name} 被定义`);
}@LogClass
class MyClass {} // 输出: "Class MyClass 被定义"
动态扩展类:
function AddMethod(target: Function) {target.prototype.newMethod = () => console.log("动态添加的方法");
}@AddMethod
class Demo {}
const obj = new Demo();
(obj as any).newMethod(); // 输出: "动态添加的方法"
方法装饰器
修改类方法的行为(如日志、拦截等):
function LogMethod(target: any,methodName: string,descriptor: PropertyDescriptor
) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`调用方法 ${methodName},参数:`, args);return originalMethod.apply(this, args);};
}class Calculator {@LogMethodadd(a: number, b: number) {return a + b;}
}const calc = new Calculator();
calc.add(2, 3); // 输出日志后返回 5
属性装饰器
用于监听属性访问或修改:
function DefaultValue(value: any) {return (target: any, propertyKey: string) => {let currentValue = value;Object.defineProperty(target, propertyKey, {get: () => currentValue,set: (newValue) => {console.log(`属性 ${propertyKey} 从 ${currentValue} 变为 ${newValue}`);currentValue = newValue;},});};
}class User {@DefaultValue("匿名")name: string;
}const user = new User();
console.log(user.name); // "匿名"
user.name = "Alice"; // 输出变更日志
参数装饰器
主要用于依赖注入(如 Angular)或参数验证:
function CheckParam(target: any, methodName: string, paramIndex: number) {console.log(`方法 ${methodName} 的第 ${paramIndex} 个参数被装饰`);
}class Validator {validate(@CheckParam input: string) {}// 输出: "方法 validate 的第 0 个参数被装饰"
}
3、装饰器工厂
通过高阶函数实现可配置的装饰器:
function LogWithPrefix(prefix: string) {return function (target: any, methodName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log(`[${prefix}] 调用方法 ${methodName}`);return originalMethod.apply(this, args);};};
}class Service {@LogWithPrefix("DEBUG")fetchData() {return "数据";}
}
4、装饰器执行顺序
- 参数装饰器 → 方法/属性装饰器 → 类装饰器
- 同类型装饰器从下到上执行(针对方法/属性)或从上到下执行(针对类)。
5、实际应用场景
AOP 编程(日志/性能监控)
function MeasureTime(target: any, methodName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {const start = performance.now();const result = originalMethod.apply(this, args);console.log(`${methodName} 执行耗时: ${performance.now() - start}ms`);return result;};
}
依赖注入(DI)
function Injectable(target: Function) {// 注册到 IoC 容器Container.register(target);
}@Injectable
class DatabaseService {}
路由绑定(如 Express/NestJS)
function Get(path: string) {return (target: any, methodName: string) => {Router.register("GET", path, target[methodName]);};
}class UserController {@Get("/users")listUsers() { /* ... */ }
}
6、注意事项
- 实验性特性:未来标准可能变化,生产环境建议结合框架使用(如 Angular/NestJS)。
- 静态限制:装饰器无法修改类/方法的静态类型信息(需配合类型断言或泛型)。
- 性能影响:过度使用装饰器可能增加启动时间。