用户工具

站点工具


typescript:第一章typescript基础

第一章:TypeScript 基础

本章概述

欢迎来到 TypeScript 的世界!本章将带你从零开始了解 TypeScript,包括安装配置、编译原理以及最基本的类型注解概念。通过本章学习,你将能够搭建 TypeScript 开发环境并编写第一个 TypeScript 程序。

1.1 什么是 TypeScript

TypeScript 是一种由 Microsoft 开发的开源编程语言,于 2012 年 10 月首次发布。它是 JavaScript 的超集(Superset),意味着任何有效的 JavaScript 代码都是有效的 TypeScript 代码。

1.1.1 TypeScript 的核心特性

静态类型系统 TypeScript 最大的特点是添加了可选的静态类型系统。这使得开发者可以在编码阶段就发现类型错误,而不是在运行时。

```typescript JavaScript - 运行时才发现错误 function add(a, b) { return a + b; } add(“1”, 2); “12” - 逻辑错误但未报错

TypeScript - 编译时就发现错误 function addTS(a: number, b: number): number { return a + b; } addTS(“1”, 2); Error: Argument of type 'string' is not assignable to parameter of type 'number' ```

ES6+ 特性支持 TypeScript 支持最新的 ECMAScript 特性,包括:

  1. 类(Class)
  2. 模块(Module)
  3. 异步函数(Async/Await)
  4. 解构赋值
  5. 箭头函数
  6. 等等

编译时转换 TypeScript 代码需要编译(转译)为 JavaScript 才能在浏览器或 Node.js 中运行。编译器会将高级语法转换为兼容目标环境的 JavaScript。

1.1.2 TypeScript vs JavaScript

特性 JavaScript TypeScript
——————————
类型系统 动态类型 静态类型(可选)
编译 解释执行 需要编译
错误检测 运行时 编译时
IDE 支持 基础 强大
学习曲线 平缓 稍陡
代码量 较少 稍多(类型注解)
维护性 一般 优秀

1.2 安装 TypeScript

1.2.1 环境要求

在开始之前,请确保你的系统已安装:

  1. Node.js(推荐 v18 或更高版本)
  2. npm 或 yarn 包管理器

检查 Node.js 版本: ```bash node –version npm –version ```

1.2.2 全局安装 TypeScript

使用 npm 全局安装 TypeScript 编译器:

```bash # 使用 npm npm install -g typescript

# 使用 yarn yarn global add typescript ```

验证安装: ```bash tsc –version # 输出类似:Version 5.3.3 ```

1.2.3 项目本地安装(推荐)

对于实际项目,建议在项目本地安装 TypeScript:

```bash # 创建项目目录 mkdir my-ts-project cd my-ts-project

# 初始化 npm 项目 npm init -y

# 本地安装 TypeScript npm install –save-dev typescript

# 或作为开发依赖 npm install -D typescript ```

本地安装后,使用 npx 运行 tsc: ```bash npx tsc –version ```

1.3 编写第一个 TypeScript 程序

1.3.1 创建 TypeScript 文件

创建一个名为 “hello.ts” 的文件:

```typescript hello.ts function greet(person: string, date: Date): string { return `Hello ${person}, today is ${date.toDateString()}!`; } const user = “TypeScript”; const today = new Date(); console.log(greet(user, today)); ``` ==== 1.3.2 编译 TypeScript ==== 使用 tsc 命令编译文件: ```bash tsc hello.ts ``` 这将生成一个同名的 JavaScript 文件 “hello.js”: ```javascript hello.js (编译输出) function greet(person, date) {

return "Hello ".concat(person, ", today is ").concat(date.toDateString(), "!");

} var user = “TypeScript”; var today = new Date(); console.log(greet(user, today)); ```

1.3.3 运行 JavaScript

```bash node hello.js # 输出:Hello TypeScript, today is Mon Jan 15 2025! ```

1.4 TypeScript 编译原理

1.4.1 编译过程概述

TypeScript 编译器(tsc)的工作流程:

``` TypeScript 源码 → 词法分析 → 语法分析 → 语义分析 → 类型检查 → 代码生成 → JavaScript 代码 ```

1. 词法分析(Lexical Analysis) 将源代码转换为 Token 序列。

2. 语法分析(Parsing) 将 Token 序列转换为抽象语法树(AST)。

3. 语义分析(Semantic Analysis) 检查语法结构的语义正确性。

4. 类型检查(Type Checking) 这是 TypeScript 的核心阶段,验证类型系统的约束。

5. 代码生成(Code Generation) 将 AST 转换为目标 JavaScript 代码。

1.4.2 类型擦除

TypeScript 的类型只在编译时存在,编译后的 JavaScript 代码中完全不包含类型信息,这个过程称为“类型擦除”(Type Erasure)。

```typescript TypeScript interface Point { x: number; y: number; } function distance(p1: Point, p2: Point): number { const dx = p1.x - p2.x; const dy = p1.y - p2.y; return Math.sqrt(dx * dx + dy * dy); } ``` 编译后: ```javascript JavaScript function distance(p1, p2) {

var dx = p1.x - p2.x;
var dy = p1.y - p2.y;
return Math.sqrt(dx * dx + dy * dy);

} ```

注意:接口定义和类型注解在编译后完全消失!

1.5 基础类型注解

1.5.1 变量类型注解

使用冒号(:)为变量添加类型注解:

```typescript 基本类型 let name: string = “Alice”; let age: number = 25; let isStudent: boolean = true; 数组类型 let numbers: number[] = [1, 2, 3, 4, 5]; let names: Array<string> = [“Alice”, “Bob”, “Charlie”];

any 类型 - 绕过类型检查 let anything: any = 4; anything = “string”; anything = true; unknown 类型 - 类型安全的 any let notSure: unknown = 4; notSure.toFixed(); Error: Object is of type 'unknown'

void - 无返回值 function logMessage(message: string): void { console.log(message); } null 和 undefined let u: undefined = undefined; let n: null = null; ```

1.5.2 函数类型注解

```typescript 函数声明 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 ⇒ { return x / y; }; 可选参数 function greet(name: string, greeting?: string): string {

if (greeting) {
  return `${greeting}, ${name}!`;
}
return `Hello, ${name}!`;

}

默认参数 function greetWithDefault(name: string, greeting: string = “Hello”): string { return `${greeting}, ${name}!`; } 剩余参数 function sum(…numbers: number[]): number {

return numbers.reduce((total, num) => total + num, 0);

} ```

1.5.3 对象类型注解

```typescript 对象字面量类型 let person: { name: string; age: number; isStudent?: boolean; 可选属性 } = {

name: "Alice",
age: 25

};

使用接口(推荐) interface Person { name: string; age: number; email?: string; } const alice: Person = { name: “Alice”, age: 25, email: “alice@example.com” }; ``` ===== 1.6 tsconfig.json 配置 ===== ==== 1.6.1 初始化配置文件 ==== ```bash tsc –init ``` 这将创建一个包含所有编译器选项的 tsconfig.json 文件。 ==== 1.6.2 基本配置示例 ==== ```json { “compilerOptions”: { 目标 JavaScript 版本

  "target": "ES2020",
  
  // 模块系统
  "module": "ESNext",
  
  // 模块解析策略
  "moduleResolution": "node",
  
  // 输出目录
  "outDir": "./dist",
  
  // 源代码目录
  "rootDir": "./src",
  
  // 启用严格模式
  "strict": true,
  
  // 允许编译 JavaScript 文件
  "allowJs": true,
  
  // 生成 source map
  "sourceMap": true,
  
  // 启用装饰器
  "experimentalDecorators": true,
  
  // 启用 ES 模块互操作
  "esModuleInterop": true,
  
  // 跳过库类型检查
  "skipLibCheck": true,
  
  // 强制文件名大小写一致
  "forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]

} ```

1.6.3 常用编译选项详解

target 指定编译后的 JavaScript 版本:“ES3”, “ES5”, “ES2015”, “ES2016”, “ES2017”, “ES2018”, “ES2019”, “ES2020”, “ESNext”

module 指定模块系统:“CommonJS”, “AMD”, “System”, “UMD”, “ES2015”, “ES2020”, “ESNext”

strict 启用所有严格类型检查选项的快捷方式,等同于开启:

  1. strictNullChecks
  2. strictFunctionTypes
  3. strictBindCallApply
  4. strictPropertyInitialization
  5. noImplicitAny
  6. noImplicitThis
  7. alwaysStrict

noImplicitAny 禁止隐式的 any 类型,要求必须为没有类型注解的变量或参数指定类型。

1.7 类型推断

TypeScript 具有强大的类型推断能力,在很多情况下不需要显式添加类型注解。

1.7.1 变量类型推断

```typescript TypeScript 会自动推断类型 let message = “Hello”; 推断为 string let count = 42; 推断为 number let isValid = true; 推断为 boolean

错误示例 message = 42; Error: Type 'number' is not assignable to type 'string' ```

1.7.2 函数返回值推断

```typescript 返回值类型可以被推断 function add(a: number, b: number) { return a + b; 推断返回值为 number }

复杂推断 function getArray() { return [1, 2, 3]; 推断为 number[] } ```

1.7.3 最佳实践:何时添加类型注解

应该添加类型注解的情况:

  1. 函数参数
  2. 函数返回值(复杂逻辑时)
  3. 类的公共属性
  4. 需要明确类型的变量

可以依赖推断的情况:

  1. 简单变量的初始化
  2. 明显能从上下文推断的类型
  3. 局部变量

```typescript 推荐:为函数参数和返回值添加类型 function calculateTotal(price: number, quantity: number): number { return price * quantity; } 推荐:复杂对象明确类型 interface User {

id: number;
name: string;

}

const users: User[] = fetchUsers();

可选:简单变量可以依赖推断 const total = calculateTotal(100, 5); const welcomeMessage = “Welcome!”; ``` ===== 1.8 类型断言 ===== 类型断言(Type Assertion)允许你告诉编译器某个值的具体类型,类似于其他语言中的类型转换。 ==== 1.8.1 语法 ==== ```typescript 尖括号语法 let someValue: any = “this is a string”; let strLength: number = (<string>someValue).length;

as 语法(推荐,特别是在 JSX 中) let strLength2: number = (someValue as string).length; ``` ==== 1.8.2 使用场景 ==== ```typescript 处理 DOM 元素 const input = document.getElementById(“user-input”) as HTMLInputElement; console.log(input.value);

处理 API 响应 interface User { name: string; age: number; } const response: any = fetchUser(); const user = response as User; 双重断言(谨慎使用) const something = “hello” as unknown as number; 强制转换 ``` ===== 1.9 字面量类型 ===== TypeScript 允许将字面量作为类型使用,提供更精确的类型约束。 ```typescript 字符串字面量类型 let direction: “north” | “south” | “east” | “west”; direction = “north”; direction = “up”; ✗ Error 数字字面量类型 type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6; let roll: DiceRoll = 4; let invalid: DiceRoll = 7; ✗ Error 布尔字面量类型 type Status = true | false;

结合使用 interface Config { mode: “development” | “production” | “test”; port: 3000 | 8080 | 9000; debug: boolean; } ``` ===== 1.10 严格模式详解 ===== ==== 1.10.1 strictNullChecks ==== ```typescript strictNullChecks: false(默认) let name: string = null; OK strictNullChecks: true let name2: string = null; Error: Type 'null' is not assignable to type 'string' 正确使用 let name3: string | null = null; OK ``` ==== 1.10.2 noImplicitAny ==== ```typescript noImplicitAny: false function log(message) { 参数隐式为 any console.log(message); } noImplicitAny: true function log2(message: any) { 必须显式声明 any console.log(message); } ``` ===== 1.11 本章小结 ===== 本章我们学习了: 1. TypeScript 基础概念 - 理解 TypeScript 是什么以及它与 JavaScript 的关系 2. 环境搭建 - 安装 TypeScript 编译器并创建第一个程序 3. 编译原理 - 了解 TypeScript 如何编译为 JavaScript 4. 类型注解 - 掌握基本类型的使用方法 5. tsconfig.json - 配置编译器选项 6. 类型推断 - 理解何时需要显式添加类型 7. 类型断言 - 在必要时覆盖类型推断 ===== 1.12 练习题 ===== ==== 练习 1:类型注解基础 ==== 为以下变量和函数添加适当的类型注解: ```typescript 待补充类型的代码 let userName = “张三”; let userAge = 25; let hobbies = [“阅读”, “编程”, “游戏”];

function greetUser(name, age) {

return `你好,${name},今年${age}岁`;

}

function calculateArea(width, height) {

return width * height;

} ```

<details> <summary>参考答案</summary>

```typescript let userName: string = “张三”; let userAge: number = 25; let hobbies: string[] = [“阅读”, “编程”, “游戏”];

function greetUser(name: string, age: number): string {

return `你好,${name},今年${age}岁`;

}

function calculateArea(width: number, height: number): number {

return width * height;

} ```

</details>

练习 2:配置 tsconfig.json

创建一个适合前端项目的 tsconfig.json 配置,要求:

  1. 目标 ES2018
  2. 使用 ES 模块
  3. 输出到 dist 目录
  4. 源代码在 src 目录
  5. 启用严格模式
  6. 生成 source map

<details> <summary>参考答案</summary>

```json {

"compilerOptions": {
  "target": "ES2018",
  "module": "ESNext",
  "moduleResolution": "node",
  "outDir": "./dist",
  "rootDir": "./src",
  "strict": true,
  "sourceMap": true,
  "esModuleInterop": true,
  "skipLibCheck": true,
  "forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]

} ```

</details>

练习 3:类型推断与断言

分析以下代码,指出哪些地方使用了类型推断,哪些地方需要类型断言:

```typescript const apiResponse = fetchData(); const userName = apiResponse.name; const userAge = apiResponse.age;

const element = document.getElementById(“input”); const value = element.value; ```

<details> <summary>参考答案与解释</summary>

```typescript const apiResponse: any = fetchData(); 需要类型,默认推断为 any const userName: string = apiResponse.name; 从上下文推断,或需要断言 const userAge: number = apiResponse.age;

需要类型断言,因为 getElementById 返回 HTMLElement | null const element = document.getElementById(“input”) as HTMLInputElement; const value = element.value; 或者先进行类型检查 const element2 = document.getElementById(“input”); if (element2 instanceof HTMLInputElement) {

const value2 = element2.value;  // 这里 TypeScript 知道类型

} ```

</details>

练习 4:字面量类型

使用字面量类型定义一个配置对象,要求:

  1. 环境只能是 “dev”, “test”, “prod” 之一
  2. 日志级别只能是 “debug”, “info”, “warn”, “error” 之一
  3. 端口号只能是 3000, 8080, 9000 之一

<details> <summary>参考答案</summary>

```typescript type Environment = “dev” | “test” | “prod”; type LogLevel = “debug” | “info” | “warn” | “error”; type Port = 3000 | 8080 | 9000;

interface AppConfig {

environment: Environment;
logLevel: LogLevel;
port: Port;

}

const config: AppConfig = {

environment: "dev",
logLevel: "debug",
port: 3000

}; ```

</details>

扩展阅读

typescript/第一章typescript基础.txt · 最后更改: 127.0.0.1