当前位置: 首页 > news >正文

TypeScript 完全指南:从 JavaScript 到类型安全的重构之路

TypeScript 是 JavaScript 的一个严格超集,它为 JavaScript 添加了可选的静态类型系统,并将代码编译为纯 JavaScript。由微软开发并开源,TypeScript 自 2012 年发布以来,已成为大型前端项目的首选语言。它不仅能提前捕获类型错误,还能提供更好的 IDE 支持(自动补全、重构、导航),让 JavaScript 开发体验提升到新的高度。本文将带你从零开始,循序渐进地掌握 TypeScript 的核心概念、高级类型、配置以及实际应用。


一、TypeScript 是什么?为什么选择它?

1.1 TypeScript 与 JavaScript 的关系

  • TypeScript 是 JavaScript 的超集,所有合法的 JavaScript 代码都是合法的 TypeScript 代码。
  • TypeScript 添加了类型注解接口泛型枚举等特性,并在编译阶段进行类型检查,然后转译为标准 JavaScript(可在任何运行 JS 的环境执行)。

1.2 核心优势

优势

说明

静态类型检查

在代码运行前发现类型错误,减少运行时 bug。

更好的 IDE 支持

类型信息使得自动补全、跳转定义、重构更加智能。

代码自文档化

类型注解本身就是文档,降低维护成本。

最新 ECMAScript 特性

支持 ES 最新语法,并可编译到指定目标版本。

强大的社区与生态

主流框架(React、Vue、Angular)和库都提供了 TypeScript 类型定义。

1.3 安装与编译

npm install -g typescript tsc --version # 查看版本

创建hello.ts

function greet(name: string): string { return `Hello, ${name}!`; } console.log(greet("TypeScript"));

编译:

bash

tsc hello.ts # 生成 hello.js

也可以使用tsc --watch监听文件变化自动编译。


二、基础类型与类型注解

2.1 基本类型

TypeScript 支持与 JavaScript 相同的类型,并增加了额外的类型注解。

类型

示例

说明

number

let age: number = 30;

整数或浮点数

string

let name: string = "张三";

文本

boolean

let isDone: boolean = false;

true/false

null

/undefined

let n: null = null;

空值

bigint

let big: bigint = 100n;

大整数 (ES2020)

symbol

let sym: symbol = Symbol();

唯一值

2.2 数组和元组

let list: number[] = [1, 2, 3]; let list2: Array<string> = ['a', 'b']; // 泛型写法 // 元组:固定长度和类型的数组 let tuple: [string, number] = ['age', 25];

2.3 枚举(enum)

枚举为一组数值赋予友好的名字。

enum Color { Red, Green, Blue } let c: Color = Color.Green; console.log(c); // 1(默认从0开始) // 可指定数值 enum Status { Success = 200, NotFound = 404 }

2.4 Any 与 Unknown

  • any:关闭类型检查,可以赋任意值,应尽量避免使用。
  • unknown:表示不确定类型,使用前必须进行类型收窄。
let notSure: any = 4; notSure = "maybe a string"; let safe: unknown = 10; if (typeof safe === 'number') { console.log(safe + 5); }

2.5 Void 与 Never

  • void:函数无返回值。
  • never:函数永远不会正常结束(抛出错误或无限循环)。
function warn(): void { console.log("warning"); } function error(): never { throw new Error("oops"); }

2.6 类型断言

当你比 TypeScript 更了解某个值的类型时,可以使用断言。

let someValue: any = "this is a string"; let strLength: number = (someValue as string).length; // 或 <string>someValue.length(JSX 中不能使用尖括号)

三、接口(Interface)

接口是 TypeScript 的核心特性,用于定义对象的结构。

3.1 基本接口

interface Person { name: string; age: number; readonly id: number; // 只读属性 email?: string; // 可选属性 } let user: Person = { name: "李四", age: 28, id: 1 }; // user.id = 2; // 错误,只读

3.2 函数类型

接口也可描述函数类型。

interface SearchFunc { (source: string, sub: string): boolean; } let mySearch: SearchFunc = function(src, sub) { return src.indexOf(sub) > -1; };

3.3 可索引类型

interface StringArray { [index: number]: string; } let arr: StringArray = ["hello", "world"];

3.4 接口继承

interface Shape { color: string; } interface Square extends Shape { sideLength: number; } let sq: Square = { color: "red", sideLength: 10 };

四、类(Class)

TypeScript 扩展了 ES6 类的特性,增加了访问修饰符和抽象类。

4.1 修饰符

  • public:默认,成员在任何地方可见。
  • private:仅在类内部可见。
  • protected:在类及其子类中可见。
  • readonly:只读属性。
class Animal { private name: string; protected age: number; public constructor(name: string, age: number) { this.name = name; this.age = age; } public move(distance: number): void { console.log(`${this.name} moved ${distance}m`); } }

4.2 抽象类与抽象方法

abstract class Vehicle { abstract start(): void; stop(): void { console.log("stopped"); } } class Car extends Vehicle { start(): void { console.log("Car started"); } }

4.3 参数属性

在构造函数参数前直接添加修饰符,可以自动创建并初始化同名属性。

class Person { constructor(public name: string, private age: number) {} } // 等价于手动定义 name、age 并赋值

五、函数与泛型

5.1 函数类型注解

function add(x: number, y: number): number { return x + y; } // 可选参数(必须放在最后) function buildName(first: string, last?: string): string { return last ? `${first} ${last}` : first; } // 默认参数 function greet(name: string = "Guest"): void { console.log(`Hello ${name}`); }

5.2 泛型(Generics)

泛型允许定义可重用的组件,支持多种类型。

function identity<T>(arg: T): T { return arg; } let output = identity<string>("myString"); let output2 = identity(100); // 类型推断为 number // 泛型接口 interface GenericFn<T> { (arg: T): T; } // 泛型类 class Stack<T> { private items: T[] = []; push(item: T): void { this.items.push(item); } pop(): T | undefined { return this.items.pop(); } }

5.3 泛型约束

使用extends限制泛型的类型范围。

interface Lengthwise { length: number; } function logLength<T extends Lengthwise>(arg: T): void { console.log(arg.length); } logLength("hello"); // 正确,string 有 length // logLength(123); // 错误,number 没有 length

六、高级类型

6.1 联合类型与交叉类型

// 联合:满足其中一个类型即可 let id: string | number; id = "abc"; id = 123; // 交叉:合并多个类型 interface A { a: string; } interface B { b: number; } type C = A & B; let obj: C = { a: "hello", b: 42 };

6.2 类型别名(Type Alias)

type可以为任意类型起别名,包括联合、元组、原始类型

type Name = string; type ID = number | string; type Point = { x: number; y: number };

6.3 字面量类型与模板字面量类型

type Direction = "up" | "down" | "left" | "right"; let move: Direction = "up"; // 模板字面量类型 type Greeting = `Hello ${string}`; let g: Greeting = "Hello world";

6.4 类型守卫(Type Guards)

通过typeofinstanceof或自定义守卫函数收窄类型。

function isNumber(x: any): x is number { return typeof x === "number"; } function padLeft(value: string, padding: string | number) { if (isNumber(padding)) { return " ".repeat(padding) + value; } return padding + value; }

6.5 索引类型与映射类型

// 索引类型查询 keyof interface Person { name: string; age: number; } type K = keyof Person; // "name" | "age" // 映射类型 type Readonly<T> = { readonly [P in keyof T]: T[P]; }; type Partial<T> = { [P in keyof T]?: T[P]; }; // 实际使用:Record<Keys, Type> type PageInfo = Record<string, number>;

6.6 条件类型

type IsString<T> = T extends string ? true : false; type A = IsString<"hello">; // true type B = IsString<number>; // false // 内置条件类型:Exclude<T, U>, Extract<T, U>, NonNullable<T> 等 type T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"

七、模块与命名空间

7.1 ES 模块

TypeScript 支持 ES 模块语法,编译时可以根据module选项转换。

// math.ts export const pi = 3.14; export function add(x: number, y: number): number { return x + y; } // app.ts import { pi, add } from "./math.js"; console.log(add(1, 2));

7.2 命名空间(旧式内部模块)

主要用于旧项目或全局代码组织,现代开发推荐使用 ES 模块。

namespace Validation { export interface StringValidator { isAcceptable(s: string): boolean; } export class LettersOnlyValidator implements StringValidator { /*...*/ } } let validator = new Validation.LettersOnlyValidator();

八、类型声明文件(.d.ts)

TypeScript 使用.d.ts文件为 JavaScript 库提供类型信息。当引入第三方库时,通常需要安装对应的类型定义包。

npm install --save-dev @types/lodash

你也可以自己编写声明文件:

// math-lib.d.ts declare module "math-lib" { export function sum(a: number, b: number): number; }

九、配置文件 tsconfig.json

在项目根目录执行tsc --init会生成tsconfig.json。常用配置项:

选项

说明

compilerOptions.target

编译目标 ES 版本(ES5、ES6、ES2020 等)

compilerOptions.module

模块系统(commonjs、esnext 等)

compilerOptions.strict

启用所有严格类型检查(推荐 true)

compilerOptions.outDir

输出目录

compilerOptions.rootDir

源码根目录

compilerOptions.esModuleInterop

兼容 CommonJS 和 ES 模块

compilerOptions.skipLibCheck

跳过声明文件检查

include

/exclude

指定要编译的文件或排除规则

示例:

{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "strict": true, "outDir": "./dist", "rootDir": "./src", "esModuleInterop": true, "skipLibCheck": true }, "include": ["src/**/*"], "exclude": ["node_modules", "**/*.test.ts"] }

十、与 React、Vue 等框架集成

10.1 React

使用create-react-app --template typescript创建项目。

interface Props { name: string; age?: number; } const Greeting: React.FC<Props> = ({ name, age }) => { return <div>Hello {name}, age {age}</div>; };

10.2 Vue 3

使用 Vite 创建 Vue + TypeScript 项目。

<script setup lang="ts"> const count = ref<number>(0); interface User { id: number; name: string; } const user = reactive<User>({ id: 1, name: "Alice" }); </script>

十一、实用技巧与最佳实践

11.1 严格模式

始终开启strict: true,它可以帮你捕获更多潜在错误。

11.2 避免使用 any

使用unknown代替any,并通过类型守卫收窄。如果实在无法确定,考虑使用@ts-expect-error注释而不是any

11.3 使用readonly防止意外修改

const config: { readonly apiUrl: string } = { apiUrl: "https://api.example.com" }; // config.apiUrl = "new"; // 错误

11.4 善用工具类型

TypeScript 内置了Partial<T>Required<T>Pick<T, K>Omit<T, K>Record<K, T>等,可以极大减少重复代码。

interface Todo { title: string; description: string; completed: boolean; } type TodoPreview = Pick<Todo, "title" | "completed">; type TodoOptional = Partial<Todo>;

11.5 使用satisfies运算符(TypeScript 4.9+)

确保表达式符合某个类型,但不改变其推断类型。

const colors = { red: [255, 0, 0], green: "#00ff00" } satisfies Record<string, [number, number, number] | string>; // colors.red 类型仍是 [number, number, number],而不被宽化为 string

十二、从 JavaScript 迁移到 TypeScript 的策略

  1. 逐步引入:将.js改为.ts,先修改低风险文件。
  2. 设置allowJs: true:混合编译 JS 和 TS。
  3. 添加// @ts-check:在 JS 文件中启用类型检查,逐步修复错误。
  4. 开启noImplicitAny: false:初期降低严格度,逐步收严。
  5. 为第三方库安装类型@types/*
  6. 最终升级到strict: true

十三、总结与进阶资源

http://www.jsqmd.com/news/935246/

相关文章:

  • 从全球数据库大会看云原生与AI融合的技术趋势与实战
  • 从“早熟收敛”到调参实战:遗传算法在Scikit-Optimize中的避坑指南
  • 2026天津黄金回收实测!添价收黄金回收对比各大品牌评测 - 薛定谔的梨花猫
  • Agent 系列(9):多 Agent 架构设计模式——Supervisor 与 Pipeline
  • 2026年被动房全产业链EPC总承包服务商深度对标:从零碳建筑设计到施工认证的完整选型指引 - 企业名录优选推荐
  • arcgis 裁剪
  • 深度访谈GPT-3:探索大型语言模型的行为边界与实用对话策略
  • SEIF Awards:软件工程研究的种子基金与创新孵化机制解析
  • 2026 东莞钢结构工厂实力排行 专业靠谱厂家精选推荐 - 变量人生001
  • NoMachine黑屏?试试用Windows远程桌面(RDP)连接你的Ubuntu/Debian
  • 用Multisim仿真555报警器:从电路图到声光效果,手把手带你复现大学经典实验
  • 别再只用线性回归了!用Python的sklearn手把手教你Lasso回归实战(含超参数alpha调优技巧)
  • 余生黄金回收——2026年5月沈阳卖金全攻略,这家五星店铺让你多卖好几克! - 余生黄金回收
  • STM32 程序加密完全指南:构建软硬一体的纵深防御体系
  • 四川省攀枝花市寄件省钱攻略:4 个全国低价寄件物流微信工具,小件快递大件物流上门全搞定 - 时讯资讯
  • SuperMap Hi-Fi 3D SDK + Unity 2019.4:从零搭建一个可交互的3D智慧城市场景(含完整代码)
  • 2026十大护颈枕头硬核盘点:支撑、透气、安全,西尼优枕头实力突出 - 每日行业榜
  • 你以为的Kiosk模式就够安全了?实测Chrome/Edge/Firefox全屏防退出方案的漏洞与加固
  • PostgreSQL 技术日报 (6月1日)|逻辑复制问题修复,AI 行业动态速览
  • CTDE范式在机器人协同任务中的优势与实践
  • GPT-3技术解析与企业智能应用:从Transformer架构到知识管理实战
  • 别再死记硬背了!用‘F谱号’的起源故事,5分钟彻底搞懂低音谱号与左手钢琴键的对应关系
  • 2026年五金模具配件厂家深度测评:如何为你的精密冲压匹配最佳方案? - 资讯快报
  • VMware vCenter 7.0日志盘告警别慌!手把手教你SSH登录清理Tomcat和PostgreSQL日志(附详细路径)
  • 杭州嘉目视科怎么样:2026配眼镜靠谱店铺排名推荐 - 每日行业榜
  • ARM虚拟化核心:HCR_EL2寄存器深度解析与实践
  • 2026成都靠谱软装硬装公司推荐|本地深耕十年装修设计施工门店优选 - 海棠依旧大
  • MySQL字符集进化史:从‘残缺’的utf8到真正的utf8mb4,我们经历了什么?
  • 从视觉暂留到动态显示:Arduino POV项目全解析
  • 从‘炼丹’到‘应用’:用 Docker 三分钟部署 OpenPose 推理服务,告别环境噩梦