2024年最新前端工程师 TypeScript 基础知识点详细教程(更新中)

1. TypeScript 概述

TypeScript 是由微软开发的、基于 JavaScript 的一种强类型编程语言。它是在 JavaScript 的基础上添加了静态类型检查、面向对象编程等功能的超集,最终会被编译为纯 JavaScript 代码。由于其扩展了 JavaScript 的功能,TypeScript 特别适合大型项目和团队协作,能够提高代码的可读性、可维护性和开发效率。

TypeScript 是由微软开发的、基于 JavaScript 的一种强类型编程语言。它是在 JavaScript 的基础上添加了静态类型检查、面向对象编程等功能的超集,最终会被编译为纯 JavaScript 代码。由于其扩展了 JavaScript 的功能,TypeScript 特别适合大型项目和团队协作,能够提高代码的可读性、可维护性和开发效率。

1.1 TypeScript 优势

提高代码质量:通过静态类型检查,TypeScript 能在编译阶段捕捉潜在的错误,从而减少运行时错误,提高代码的稳定性。更好的协作:类型信息使得团队中的其他开发者能够更容易理解代码结构和预期行为,改善协作效率。增强的开发工具:由于 TypeScript 是强类型语言,编辑器可以提供更好的代码补全、重构支持,以及更加详细的错误提示。兼容 JavaScript:TypeScript 是 JavaScript 的超集,意味着所有的 JavaScript 代码都是合法的 TypeScript 代码。可以逐步将现有的 JavaScript 项目迁移到 TypeScript。面向大型项目:TypeScript 特别适合开发大型代码库,因为它提供了更严格的类型检查和结构化的开发方式,确保代码更易于维护。

1.2 TypeScript 和 JavaScript 区别

TypeScript 和 JavaScript 在类型系统、编译过程、特性支持以及开发体验等方面存在显著差异。TypeScript 通过引入静态类型系统和一系列新特性,为 JavaScript 开发提供了更好的支持和保障。然而 JavaScript 作为一种广泛应用的脚本语言,其灵活性和动态性也是其独特优势之一。因此,在选择使用 TypeScript 还是 JavaScript 时,需要根据具体的项目需求和团队技术栈来做出决策。

类型系统区别

JavaScript:JavaScript是一种动态类型语言,其变量的类型是在运行时确定的,并且可以随时更改。这意味着在JavaScript中,你不需要(也不能)在编写代码时显式地声明变量的类型。

TypeScript:TypeScript引入了静态类型系统,允许开发者在编写代码时显式地声明变量、函数参数和返回值的类型。这使得TypeScript能够在编译时检查代码中的类型错误,提供更早的错误检测和更好的代码健壮性。

编译过程区别

JavaScript:JavaScript 代码可以直接在浏览器或者 Node.js 环境中运行,无需编译。它是一种解释型语言,代码在执行过程中被逐行解释。

TypeScript:TypeScript 代码需要通过编译器(如TypeScript Compiler,简称 tsc)将其编译成 JavaScript 代码,然后才能在浏览器或 Node.js 环境中运行。这个编译过程包括了类型检查、代码转换等步骤,确保了代码的质量。

特性支持区别

JavaScript:虽然 JavaScript 拥有广泛的应用和强大的生态系统,但其本身在类型检查、模块化、面向对象编程等方面存在局限性。不过,随着 ECMAScript 标准的不断发展,JavaScript 也在逐渐引入新的特性和语法来弥补这些不足。

TypeScript:TypeScript 在 JavaScript 的基础上添加了类型注解、接口、类、泛型等特性,使得代码更加结构化、可组织性更强,并且更易于维护和重构。此外 TypeScript 还支持 ECMAScript 的各个版本,并添加了一些额外的语言特性和功能。

开发体验区别

JavaScript:由于 JavaScript 的动态类型和解释型特性,开发者在编写代码时可能会遇到一些难以追踪的错误。此外,缺乏类型检查也使得代码的可读性和可维护性受到一定影响。

TypeScript:TypeScript 的静态类型系统、类型注解和类型推断等功能能够显著提高代码的可读性和可维护性。同时,TypeScript 还提供了强大的开发工具支持(如 Visual Studio Code 等),这些工具能够提供代码补全、类型检查、重构等功能,从而进一步提升开发效率。

特性JavaScriptTypeScript
类型系统动态类型静态类型,可选
编译不需要编译,直接运行需要编译为 JavaScript 运行
支持面向对象编程有限支持完整支持类、接口、抽象类等
开发工具支持基础代码补全强大的代码补全、类型推断、错误提示
泛型不支持支持

1.3 TypeScript 适用场景

大型项目:在大型项目中,代码的复杂度增加,TypeScript 的类型系统和模块化特性能够极大提升代码的可维护性和可扩展性。团队合作:TypeScript 能够在多人协作时提供统一的类型约束,减少沟通成本,避免类型不匹配导致的问题。需要高代码质量和安全性:如果项目要求严格的代码质量和运行时安全,TypeScript 提供的类型检查和编译时错误提示非常有用。

1.4 TypeScript 官方网站

官网提供了详尽的文档,包括TypeScript的入门指南、手册、教程等,帮助用户从基础到高级逐步掌握TypeScript。文档中包含了TypeScript的语法、类型系统、接口、泛型、枚举等核心概念的解释和示例。

中文官网:https://www.tslang.cn/
英文官网:https://www.typescriptlang.org/

在这里插入图片描述

2. TypeScript 特性

TypeScript 通过引入静态类型检查、提供更好的开发工具支持和增强代码可维护性等特性,提升了 JavaScript 的开发体验,使得代码更健壮、可靠,并且更易于协作和扩展。它适用于大型项目和团队开发,为 JavaScript 开发者提供了更强大的工具和能力。

2.1 静态类型(Static Typing)

TypeScript 允许开发者为变量、函数参数和返回值等指定类型,并在编译时进行类型检查。这有助于捕捉潜在的错误,并在编写代码时提供更好的代码提示和自动补全。

let age: number = 30;
let name: string = "John";
let isActive: boolean = true;function greet(userName: string): string {return `Hello, ${userName}`;
}

2.2 类型推断(Type Inference)

虽然 TypeScript 需要为变量指定类型,但如果没有明确指定类型,TypeScript 会根据上下文自动推断类型。这使得 TypeScript 在保证类型安全的同时,依然保持了编写 JavaScript 的简洁性。

let count = 10; // TypeScript 自动推断 count 的类型为 number

2.2 接口(Interfaces)

接口是 TypeScript 中的核心概念之一,它用于定义对象的结构。接口规定了对象必须包含的属性和方法。接口可以在类、函数参数、对象定义中使用,以确保代码的一致性和类型安全。

interface Person {name: string;age: number;greet(): void;
}let user: Person = {name: "Alice",age: 25,greet() {console.log("Hello!");}
};

2.3 类和继承(Classes and Inheritance)

TypeScript 完全支持面向对象编程,包括类、继承、接口实现、访问控制修饰符(例如: publicprivateprotected)。TypeScript 的类与 ES6 类语法非常类似,但它提供了更多功能,如抽象类和成员可见性控制。

class Animal {constructor(public name: string) {}move(distance: number) {console.log(`${this.name} moved ${distance} meters.`);}
}class Dog extends Animal {bark() {console.log("Woof! Woof!");}
}const dog = new Dog("Buddy");
dog.bark();
dog.move(10);

2.4 泛型(Generics)

TypeScript 支持泛型(Generics),使得函数、类和接口可以更灵活地处理不同的数据类型,同时保持类型安全。这对于创建可重用的组件非常有用,特别是在处理集合或映射类型时。

function identity<T>(arg: T): T {return arg;
}let output = identity<string>("Hello");
let output2 = identity<number>(123);

2.5 枚举(Enums)

枚举允许为一组相关的值定义有意义的名字,提供了更具可读性的代码。

enum Color {Red,Green,Blue}let c: Color = Color.Green;

2.6 类型别名(Type Aliases)

类型别名可以为类型定义一个简洁的名称,尤其适用于联合类型(Union Types)、交叉类型(Intersection Types)等复杂类型的场景。

   type StringOrNumber = string | number;let value: StringOrNumber = "Hello";value = 123; // 也可以是数字

2.7 模块系统(Modules)

TypeScript 使用 ES6 的模块系统,可以使用 importexport 来组织代码。模块使得代码更加模块化、易于管理和复用。

utils.ts

export function add(x: number, y: number): number {return x + y;
}

main.ts

import { add } from './utils';
console.log(add(2, 3));

2.8 工具支持和开发体验

TypeScript 通过静态类型和类型检查,提供了强大的代码自动补全、重构和错误检测功能。大多数现代 IDE(如 Visual Studio Code、WebStorm)都提供了对 TypeScript 的良好支持,能够极大提升开发体验。

TypeScript 是一种在 JavaScript 之上扩展的语言,通过引入静态类型检查、面向对象特性和丰富的工具支持,极大地提升了代码的可维护性、可读性和开发效率。无论是大型项目还是小型应用,TypeScript 都能为开发者提供更好的编程体验。

3. 编译 TypeScript

要编译 TypeScript 代码,需要使用 TypeScript 编译器(tsc),这是 TypeScript 官方提供的编译工具。编译 TypeScript 非常简单,主要步骤包括安装 TypeScript 编译器、编写 .ts 文件、使用 tsc 命令编译,并运行编译生成的 JavaScript 文件。通过 tsconfig.json,可以定制编译选项和简化编译流程。下面是编译 TypeScript 代码的详细步骤。

3.1 安装 TypeScript 编译器

首先,你需要在本地环境中安装 TypeScript 编译器。可以通过 npm(Node.js 的包管理工具)来安装 TypeScript。此命令会全局安装 TypeScript 编译器,安装完成后,可以在命令行中使用 tsc 命令。

npm install -g typescript

3.2 编写 TypeScript 代码

创建一个扩展名为 .ts 的文件,例如 example.ts,并编写一些 TypeScript 代码。

example.ts

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

3.3 编译 TypeScript 文件

在终端或命令行中,使用 tsc 命令编译 TypeScript 文件。运行此命令后,TypeScript 编译器会将 example.ts 编译为 JavaScript 文件,生成一个名为 example.js 的文件。

tsc example.ts

example.js(编译后 JavaScript)

function greet(name) {return "Hello, " + name + "!";
}
var user = "World";
console.log(greet(user));

3.4 执行编译后 JavaScript

编译完成后,生成的 JavaScript 文件可以直接在任何支持 JavaScript 的环境中运行,例如 Node.js 或浏览器。用 Node.js 来运行编译后的 example.js 文件。

node example.js

输出结果

Hello, World!

3.5 使用 tsconfig.json 文件(可选)

在实际项目中,可以通过创建一个 tsconfig.json 文件来配置 TypeScript 编译选项,从而简化编译过程。首先运行以下命令来生成 tsconfig.json 文件。

tsc --init

生成的 tsconfig.json 文件会包含多种编译选项,可以根据项目需求修改。

{"compilerOptions": {"target": "es6",                // 指定 ECMAScript 目标版本"module": "commonjs",           // 指定模块系统"strict": true,                 // 启用所有严格类型检查选项"outDir": "./dist",             // 输出文件夹"rootDir": "./src",             // 输入文件夹"esModuleInterop": true         // 支持 ES 模块的互操作性},"include": ["src/**/*"],          	// 要编译的文件"exclude": ["node_modules"]       	// 排除的文件
}

当前工作目录有 tsconfig.json 文件后,你只需在当前工作目录运行 tsc 命令即可编译整个项目,不需要再进行逐个指定文件操作。

tsc

3.6 监视文件自动编译(可选)

可以使用 --watch 选项,让 TypeScript 在文件更改时自动重新编译。

tsc --watch

3.7 TypeScript 编译选项

TypeScript 编译器提供了很多选项,你可以在 tsconfig.json 中配置,也可以在命令行中使用。

--target:指定 ECMAScript 目标版本(如 ES5、ES6)。
--module:指定模块系统(如 `commonjs`、`esnext`)。
--outDir:指定编译输出的文件夹。
--strict:启用严格模式,包括所有类型检查规则。

4. 基本数据类型语法

TypeScript 的类型声明用于为变量、函数、类等指定数据类型,使得代码更加严谨和可读。类型声明是 TypeScript 区别于 JavaScript 的重要特性之一,它帮助开发者在编译时发现潜在的类型错误。

4.1 常用基本类型

number: 			用于数字类型(包括整数和浮点数)。
string: 			用于字符串类型。
boolean: 			用于布尔类型,truefalse。
array: 				用于数组类型,可以指定数组中元素的类型。
tuple: 				元组类型,可以指定不同索引上的元素类型。
enum: 				枚举类型,用于定义一组命名常量。
any: 				任意类型,用于绕过类型检查。
void: 				用于函数没有返回值时。
null 和 undefined: 	分别表示空值和未定义值。
never: 				表示永远不会发生的类型(如抛出异常或无限循环的函数)。

基本类型

let age: number = 30;
let username: string = "Alice";
let isActive: boolean = true;

数组类型

let numbers: number[] = [1, 2, 3, 4];
let names: string[] = ["Alice", "Bob", "Charlie"];

元组类型

let person: [string, number] = ["Alice", 30];

枚举类型

enum Direction {Up = 1,Down,Left,Right
}
let dir: Direction = Direction.Up;

any 类型

let anything: any = 42;
anything = "hello";  // 可以赋值为任何类型

void 类型

function logMessage(message: string): void {console.log(message);
}

never 类型

function throwError(errorMsg: string): never {throw new Error(errorMsg);
}

TypeScript 类型推断(Type Inference)是指在不显式声明类型的情况下,TypeScript 编译器自动推断出变量、函数等的类型。类型推断能够减少代码中的显式类型声明,使代码更加简洁,同时仍然保持强类型检查的优势。

4.2 any 数据类型语法

any 是 TypeScript 中的一个特殊数据类型,它可以表示任意类型的数据。使用 any 类型时,相当于关闭了 TypeScript 的类型检查机制,允许该变量持有任意类型的值。虽然 any 提供了极大的灵活性,但会牺牲掉 TypeScript 的类型安全优势,因此建议在必要时使用。

声明变量 any 类型

let value: any;value = 123;         // 可以是 number
value = "hello";     // 可以是 string
value = true;        // 可以是 boolean
value = {};          // 可以是 object
value = [1, 2, 3];   // 可以是 array

在这个例子中,value 变量可以存储任何类型的数据,因为它被显式地声明为 any 类型。

跳过类型检查

使用 any 类型时,TypeScript 不会对该变量进行类型检查。这使得可以绕过一些严格的类型规则。

let value: any = 5;value = "hello";  // 类型检查器不会报错
value.foo();      // 即使调用不存在的方法,也不会报错

上面的代码不会引发 TypeScript 的类型检查错误,即使 value 是一个字符串而不是对象,也不会对 foo() 方法进行类型检查。

函数参数和返回值类型: any

你可以将函数的参数或返回值声明为 any 类型,允许传入或返回任意类型的数据。

function processData(data: any): any {return data;
}let result = processData("hello");  // 返回值可以是任意类型
result = processData(123);

any 和 其他类型混合使用

在需要灵活性的情况下,可以将 any 类型与其他类型混合使用。例如,当你处理外部库的输入、解析 JSON 数据或者在逐步迁移到 TypeScript 的代码中,你可能需要使用 any

let mixed: any[] = [1, "hello", true];  // 数组可以包含任意类型的元素

any 类型安全问题

尽管 any 可以提供极大的灵活性,但过度使用它可能会导致类型错误难以捕捉。下面是一个例子,展示了如何使用 any 会导致潜在的错误。

let data: any = "hello";
console.log(data.toFixed(2));

问题:编译时不会报错,但运行时会抛出错误,因为 data 实际上是一个字符串,而不是数字。

anyunknown 区别

any 是最宽松的类型,不进行任何检查。unknown 是一种更安全的任意类型,使用 unknown 时必须进行类型检查,确保使用的值类型是正确的。

let valueAny: any = "hello";
let valueUnknown: unknown = "hello";valueAny.trim();           // 不会报错
valueUnknown.trim();       // 报错,必须先进行类型检查if (typeof valueUnknown === "string") {valueUnknown.trim();   // 类型检查后才允许操作
}

any 允许你绕过 TypeScript 的类型检查系统,但滥用它会导致类型安全性降低。为了在代码中保持类型安全,应该尽量少用 any,或者在必要的场景下使用。

any 使用场景

逐步迁移 JavaScript 代码到 TypeScript:当你将 JavaScript 代码迁移到 TypeScript,但还没有足够时间为所有内容添加类型时,可以临时使用 any

处理动态内容:例如解析 JSON 数据或使用第三方库时,输入可能是不确定的类型,这时可以使用 any 来表示动态类型。

4.3 unknown 数据类型语法

unknown 是 TypeScript 中用于表示未知类型的类型。它比 any 更安全,因为在使用 unknown 类型的值之前,必须先进行类型检查。这让 unknown 成为一种更严格的 “任意类型”。

使用 unknown 时,你不能随意对其进行操作,必须先确定它的具体类型,否则编译器会报错。这有助于在处理不确定类型时增加类型安全性。

声明 unknown 类型

let value: unknown;value = 123;       // 可以是 number
value = "hello";   // 可以是 string
value = true;      // 可以是 boolean
value = {};        // 可以是 object
value = [1, 2, 3]; // 可以是 array

unknown 类似于 any,它可以保存任何类型的值,但你不能对其进行操作,除非先进行类型检查。

unknown 类型检查

在对 unknown 类型的值进行任何操作之前,必须先进行类型检查。TypeScript 强制要求在调用方法或进行其他操作前明确类型。

let value: unknown = "hello";value.trim();  						// 错误: 类型“unknown”上不存在属性“trim”// 进行类型检查
if (typeof value === "string") {console.log(value.trim());  		// 正确:value 现在被认为是 string
}if (typeof value === "number") {console.log(value.toFixed(2));  	// 正确:value 现在被认为是 number
}

函数参数和返回值:unknown

你可以将函数的参数或返回值声明为 unknown,这样调用者必须先检查类型,才能对返回的值进行操作。

function processValue(value: unknown) {if (typeof value === "string") {return value.trim();} else if (typeof value === "number") {return value.toFixed(2);}return null;
}let result = processValue("  hello  ");  // 正确:返回 "hello"
let result2 = processValue(123);         // 正确:返回 "123.00"

unknown 类型断言

如果你确定某个 unknown 类型的值是某种类型,你可以使用类型断言来告诉 TypeScript 编译器这个值的类型。

let value: unknown = "hello";
console.log((value as string).trim());  // 使用类型断言,告诉编译器这是一个 string

类型断言不会做运行时检查,但它允许你在编译时绕过类型检查。使用时需要谨慎,确保类型断言是正确的。

unkown 与 never 的区别

unknown:表示一个未知的类型,使用前需要进行类型检查。
never:表示不可能的类型,例如永远不会返回的函数。
function throwError(message: string): never {throw new Error(message);  		// 这个函数永远不会正常结束
}	let value: unknown = "hello";
if (typeof value === "string") {console.log(value);  			// value 现在是 string
}

unknown 总结

unknown 是处理未知类型时的一种推荐选择,它在提供灵活性的同时,确保了类型安全。unknown 是一个比 any 更安全的类型,当你需要处理任意类型的值但又希望保留类型安全时,使用 unknown 是一种更好的选择。在操作 unknown 类型的值之前,必须进行类型检查,否则会引发编译错误。unknown 强制开发者在使用值时明确其类型,减少了潜在的类型错误。

4.4 never 数据类型语法

never 是 TypeScript 中的一个特殊类型,表示那些永远不会有返回值的类型。never 类型不同于 void,因为 void 表示函数可以正常返回 undefined,而 never 表示函数永远不会成功地返回。

never 数据类型 使用场景

1. 无法到达的代码:例如总是抛出错误的函数,或包含无限循环的函数。
2. 类型保护中的穷尽性检查:当你在 `switch` 或 `if` 语句中处理了所有可能的类型,`never` 可以帮助确保没有遗漏。

never 抛出异常函数

当函数抛出异常且永远不会正常返回时,返回类型为 never。在例子中,throwError 函数会抛出错误,而不会返回任何值,因此其返回类型是 never

function throwError(message: string): never {throw new Error(message);
}

never 无限循环函数

如果一个函数包含无限循环,它永远不会返回,因此返回类型也是 never。在这个例子中,infiniteLoop 函数将永远执行,不会返回任何值,因此其返回类型是 never

function infiniteLoop(): never {while (true) {// 无限循环,永远不会返回}
}

never 穷尽性检查

never 类型在类型保护和穷尽性检查中非常有用。假设我们有一个类型联合,并在 switch 语句中处理每个类型。never 可以确保所有的类型都被正确处理。

type Animal = 'cat' | 'dog';function checkAnimal(animal: Animal) {switch (animal) {case 'cat':console.log("It's a cat");break;case 'dog':console.log("It's a dog");break;default:// 如果没有处理完所有可能的情况,TS 编译器会报错const _exhaustiveCheck: never = animal;throw new Error(`Unhandled case: ${animal}`);}
}

在这个例子中,default 分支中的 animal 被赋值为 never 类型,因为理论上它应该已经处理了 Animal 类型的所有可能值。如果新增一种 Animal 类型但没有处理,TypeScript 会报错,提醒开发者更新代码。

never 区别 voidnever

void:表示函数可以返回,但返回值是 `undefined`,也就是说它是 "没有返回值" 的一种形式。
never:表示函数永远不会返回,即要么抛出异常,要么进入无限循环。
function returnVoid(): void {console.log("This function returns undefined implicitly.");
}function returnNever(): never {throw new Error("This function never returns.");
}

运行结果

returnVoid 函数可以正常执行并返回 `undefined`。
returnNever 函数永远不会执行到返回点。

never 数据类型总结

never 表示一个函数永远不会返回值,或者某些代码路径永远不会到达。它常用于抛出错误、无限循环以及类型保护中的穷尽性检查。never 提供了额外的类型安全,确保代码处理了所有可能的情况。

4.5 enum(枚举)数据类型语法

在 TypeScript 中,enum(枚举)是一种特殊的数据类型,用于定义一组命名的常量。通过使用枚举,可以为一组相关的值创建人类可读的名字,而不仅仅是使用简单的数字或字符串。枚举使代码更加可读和易于维护。

enum 枚举类型

数字枚举(Numeric Enums)
字符串枚举(String Enums)
异构枚举(Heterogeneous Enums)
常量枚举(Constant Enums)

enum 数字枚举:定义

数字枚举是最常见的枚举形式,枚举成员的值是自动递增的数字。在这个例子中,Direction.Up 的值默认为 0,接下来的 DownLeftRight 依次递增,分别为 123。如果你不提供初始值,TypeScript 会自动从 0 开始递增。

enum Direction {Up,Down,Left,Right
}let dir: Direction = Direction.Up;
console.log(dir);  // 输出 0

enum 数字枚举:手动赋值

你可以为枚举成员手动指定初始值,后续的成员依次递增。在这个例子中,Up 被显式设置为 1,而 DownLeftRight 的值依次递增为 234

enum Direction {Up = 1,Down,Left,Right
}console.log(Direction.Up);    // 输出 1
console.log(Direction.Down);  // 输出 2

enum 数字枚举:随机值

你也可以为每个成员手动指定值,而不依赖递增规则。

enum Direction {Up = 1,Down = 5,Left = 10,Right = 15
}console.log(Direction.Left);  // 输出 10

enum 字符串枚举

字符串枚举允许将每个成员定义为一个字符串字面量。这对于需要有明确文本表示的情况非常有用。在字符串枚举中,每个枚举成员都需要手动赋值为字符串,并且不再自动递增。

enum Direction {Up = "UP",Down = "DOWN",Left = "LEFT",Right = "RIGHT"
}let dir: Direction = Direction.Left;
console.log(dir);  // 输出 "LEFT"

enum 异构枚举

枚举也可以同时包含数字和字符串成员,这称为异构枚举。虽然可以定义异构枚举,但这种用法一般较少见,除非有特别的需求。

enum BooleanLikeHeterogeneousEnum {No = 0,Yes = "YES"
}console.log(BooleanLikeHeterogeneousEnum.No);   // 输出 0
console.log(BooleanLikeHeterogeneousEnum.Yes);  // 输出 "YES"

enum 反向映射

对于数字枚举,TypeScript 会为枚举成员生成双向映射(反向映射)。这意味着可以通过枚举的名称获取对应的值,也可以通过枚举的值获取对应的名称。这里,Direction[0] 返回 "Up",这是因为 TypeScript 自动创建了从数字到枚举名称的反向映射。

enum Direction {Up,Down,Left,Right
}console.log(Direction.Up);         // 输出 0
console.log(Direction[0]);         // 输出 "Up"

注意:字符串枚举没有反向映射。

enum 常量枚举

TypeScript 还提供了 const enum,用于定义常量枚举。常量枚举在编译时被内联,从而不会生成额外的 JavaScript 代码。常量枚举在编译后直接内联,生成的代码没有枚举对象,从而提高性能并减少代码量。

const enum Direction {Up,Down,Left,Right
}let dir: Direction = Direction.Up;
console.log(dir);  // 输出 0

enum 枚举类型

你可以将枚举作为类型使用,表示变量或参数只能是枚举中的值。

enum Direction {Up,Down,Left,Right
}function move(direction: Direction) {console.log("Moving", Direction[direction]);
}move(Direction.Up);   // 输出: "Moving Up"
move(5);              // 错误,5 不是 Direction 中的一个值

enum 枚举数据类型总结

enum 是 TypeScript 中用于定义一组命名常量的工具,可以是数字或字符串。数字枚举可以自动递增,字符串枚举需要显式赋值。枚举成员可以通过双向映射访问(数字枚举有反向映射,字符串枚举没有)。const enum 可以用于性能优化,在编译时直接内联枚举值。

4.6 元组(tuple)数据结构语法

在 TypeScript 中,元组(Tuple) 是一种特殊的数组类型,用于定义一组已知数量和类型的元素。与普通的数组不同,元组中的每个元素都可以有不同的类型,并且元素的数量是固定的。

元组(Tuple)定义

通过在方括号中指定类型列表来定义元组。

let myTuple: [string, number];
myTuple = ["hello", 42];  // 正确
myTuple = [42, "hello"];  // 错误:类型顺序不匹配

在这个例子中,myTuple 是一个包含两个元素的元组,第一个元素是 string 类型,第二个元素是 number 类型。

访问、操作 tuple 元组

普通数组一样访问和操作元组的元素。

let myTuple: [string, number];
myTuple = ["hello", 42];console.log(myTuple[0]); // 输出: "hello"
console.log(myTuple[1]); // 输出: 42

元组中的元素有各自的类型,可以使用这些类型进行操作。

myTuple[0] = "world"; // 正确
myTuple[1] = 99;      // 正确

tuple 可选元素

元组的某些元素可以是可选的,通过在类型后面加上 ? 表示可选元素。在这个例子中,元组的第二个元素是可选的,所以你可以只提供第一个元素。

let myTuple: [string, number?];
myTuple = ["hello"];    // 正确
myTuple = ["hello", 42]; // 正确

tuple 使用展开运算符

你可以在元组类型中使用展开运算符(...),以支持不定数量的某种类型的元素。举例这里,元组的第一个元素是字符串,接下来的元素可以是任意数量的数字。

let myTuple: [string, ...number[]];
myTuple = ["hello"];           // 正确
myTuple = ["hello", 1, 2, 3];  // 正确

tuple 元组类型使用场景

元组通常用于表示一个固定结构的数据,比如函数的返回值。

function useTuple(): [string, number] {return ["result", 200];
}const result = useTuple();
console.log(result[0]);  // 输出: "result"
console.log(result[1]);  // 输出: 200

tuple 元组类型限制

元组的长度是固定的,超出或少于指定长度都会导致编译错误。元组中的每个元素都有明确的类型和顺序。

let myTuple: [string, number];
myTuple = ["hello", 42];       // 正确
myTuple = ["hello"];           // 错误:缺少第二个元素
myTuple = ["hello", 42, 99];   // 错误:元素过多

tuple 元组类型总结

元组是一种已知长度和类型的数组,每个位置上的元素类型可以不同。元组常用于表示固定结构的数据,比如多类型的函数返回值。元组的长度和类型是严格受限的,不能随意更改。

5. 数据类型推断

TypeScript 类型推断(Type Inference)是指在不显式声明类型的情况下,TypeScript 编译器自动推断出变量、函数等的类型。类型推断能够减少代码中的显式类型声明,使代码更加简洁,同时仍然保持强类型检查的优势。

TypeScript 的类型推断机制可以自动为变量、函数、对象等推断出适当的类型,大大减少了显式类型声明的需求,同时保留了类型检查的优势。在绝大多数情况下,TypeScript 都能够根据代码的上下文推断出最合适的类型,从而使代码简洁、灵活并且安全。

5.1 变量声明类型推断

当声明变量时,如果初始化时赋值了某个值,TypeScript 会根据这个值推断出变量的类型,而不需要显式指定类型。

let age = 25;      		// 推断为 number
let name = "Alice";     // 推断为 string
let isActive = true;    // 推断为 booleanlet someVar;            // 推断为 any (如果没有赋值,推断为 `any` 类型)
someVar = 10;
someVar = "hello";

5.2 函数返回值类型推断

TypeScript 会根据函数的返回值自动推断出函数的返回类型,而不需要显式地指定返回类型。

function add(a: number, b: number) {return a + b;  // 推断为 number
}function greet() {return "Hello, World!";  // 推断为 string
}

在上面的例子中,add 函数返回 number 类型,greet 函数返回 string 类型,TypeScript 自动推断出返回值的类型,而不需要显式声明。

5.3 上下文类型推断

有时,类型是根据上下文来推断的。例如,事件处理函数、回调函数的参数类型可以由上下文自动推断出来。在这个例子中,TypeScript 根据 window.onmousedown 的上下文,推断出 event 是一个 MouseEvent 对象,自动为 event 提供了类型。

window.onmousedown = function(event) {console.log(event.button);  // `event` 自动推断为 MouseEvent 类型
};

5.4 数组类型推断

当声明数组时,TypeScript 会根据数组中的元素类型推断出整个数组的类型。

let numbers = [1, 2, 3];  					// 推断为 number[]
let names = ["Alice", "Bob", "Charlie"];  	// 推断为 string[]

如果数组包含不同类型的元素,TypeScript 会推断为联合类型。

let mixed = [1, "Alice", true];  // 推断为 (number | string | boolean)[]

5.5 对象字面量类型推断

TypeScript 可以根据对象字面量自动推断出对象的类型。

let person = {name: "Alice",age: 30
};  // 推断为 { name: string; age: number }

5.6 最佳通用类型 Best Common Type

最佳通用类型(Best Common Type)当一个数组中有多个不同类型的元素,TypeScript 会尝试推断出一个能够兼容所有元素的“最佳通用类型”。在这个例子中,TypeScript 根据数组中的元素自动推断出数组的类型为 string | number | boolean 的联合类型,因为这是最能兼容所有元素的类型。

let array = [1, 2, "hello", true];  // 推断为 (string | number | boolean)[]

5.7 返回值类型推断

函数的参数和返回值类型可以基于上下文进行推断。例如,回调函数的参数类型可以根据函数调用的上下文进行推断。

let numbers = [1, 2, 3];numbers.forEach((num) => {console.log(num);  // `num` 自动推断为 number
});

5.8 类型声明推断

在某些情况下,你可以同时使用类型推断和显式类型声明。例如,你可以为函数参数声明类型,而让 TypeScript 自动推断返回值类型。

function multiply(a: number, b: number) {return a * b;  // TypeScript 自动推断返回值为 number
}

5.9 类型兼容性推断

在推断过程中,TypeScript 会根据赋值的上下文检查类型的兼容性。如果推断出的类型与上下文不兼容,TypeScript 会报错。

let num = 10;  // 推断为 number
num = "hello"; // 报错:不能将类型 "string" 分配给类型 "number"

5.10 泛型类型推断

TypeScript 也可以在使用泛型时自动推断出类型。例如,当你调用一个泛型函数时,TypeScript 会根据传递的参数自动推断出泛型的类型。

function identity<T>(arg: T): T {return arg;
}let output1 = identity(10);   		// TypeScript 推断 T 为 number
let output2 = identity("hello");  	// TypeScript 推断 T 为 string

6. TypeScript 面向对象(更新中)

更新中···

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/147411.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux 21】线程安全

文章目录 &#x1f308; 一、线程互斥⭐ 1. 线程间互斥的相关概念&#x1f319; 1.1 临界资源和临界区&#x1f319; 1.2 互斥和原子性 ⭐ 2. 互斥量 mutex⭐ 3. 互斥量接口&#x1f319; 3.1 初始化互斥量&#x1f319; 3.2 销毁互斥量&#x1f319; 3.3 互斥量上锁&#x1f3…

Mysql删库跑路,如何恢复数据?

问题 删库跑路&#xff0c;数据还能恢复吗&#xff1f; 我们经常听说某某被领导训斥了&#xff0c;对领导心生痛恨&#xff0c;然后登录 Mysql 删库跑路。对于闲聊中经常听说过的一个段子&#xff0c;在现实生活中是否真的发生过&#xff0c;如果发生了&#xff0c;我们该如何解…

解决RabbitMQ设置x-max-length队列最大长度后不进入死信队列

解决RabbitMQ设置x-max-length队列最大长度后不进入死信队列 问题发现问题解决方法一&#xff1a;只监听死信队列&#xff0c;在死信队列里面处理业务逻辑方法二&#xff1a;修改预取值 问题发现 最近再学习RabbitMQ过程中&#xff0c;看到关于死信队列内容&#xff1a; 来自队…

Docker 容器技术:颠覆传统,重塑软件世界的新势力

一、Docker简介 什么是docker Docker 是一种开源的容器化平台&#xff0c;它可以让开发者将应用程序及其所有的依赖项打包成一个标准化的容器&#xff0c;从而实现快速部署、可移植性和一致性。 从功能角度来看&#xff0c;Docker 主要有以下几个重要特点&#xff1a; 轻量…

[Redis][数据类型]详细讲解

1.Redis 特殊数据结构 1.Streams 应用场景&#xff1a;主要用为队列(阻塞队列) 2.Geospatial 应用场景&#xff1a;用来存储坐标(经纬度) 3.HyperLogLog 应用场景&#xff1a;估算集合中的元素个数注意&#xff1a; HyperLogLog不存储元素的内容&#xff0c;但是能够记录“…

计算机毕设设计推荐-基于python+Djanog大数据的电影数据可视化分析

精彩专栏推荐订阅&#xff1a;在下方主页&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主页&#xff1a;计算机毕设木哥&#x1f525; &#x1f496; 文章目录 一、电影数据可视…

JavaWeb--纯小白笔记04:Tomcat整合IDEA

IDEA整合Tomcat 1.点击Idea的导航栏里的Run&#xff0c;选择Edit Configurations 2.点击左上角的""&#xff0c;向下翻找到Tomcat Server 选择里面的Local 3.创建一个web工程&#xff0c;点击IDEA的File-->new-->project 然后选择Java Enterprise&#xff0c;…

crosscrossover24支持的游戏有那些

CrossOver刚刚更新了24版本&#xff0c;支持《地平线零之曙光》、《以撒的结合&#xff1a;重生》等游戏。一起来看看它有哪些更新吧&#xff01;之前买过23版的用户可以在1年之内免费升级哦&#xff0c;点击这里查看升级教程。 一、功能优化 - 更新 Wine 至最新的稳定版 Wine …

七彩云南文化旅游网站设计与实现

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装七彩云南文化旅游网站软件来发挥其高效地信息处理的作用&am…

[机器学习]04-逻辑回归(python)-03-API与癌症分类案例讲解

逻辑回归&#xff08;Logistic Regression&#xff09; 的一API 介绍 关于如何配置模型中的优化器、正则化和惩罚项。 1. 逻辑回归 API 在 Scikit-learn 中&#xff0c;逻辑回归可以通过如下方式定义&#xff1a; from sklearn.linear_model import LogisticRegression ​ …

Web 安全(Web Security)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

Renesas R7FA8D1BH (Cortex®-M85)的 General PWM的应用实践

目录 概述 1 General PWM介绍 1.1 特性 1.2 定时器选择注意点 2 时钟配置 3 应用案例 3.1 基本定时器应用 3.2 定时器回调函数案例 3.3 输入捕捉功能案例 3.4 更新周期案例 3.5 更新占空比案例 3.6 单次触发脉冲案例 4 测试 4.1 代码介绍 4.2 验证 概述 本文主…

算法练习题25——leetcode3279统计重新排列后包含另一个字符串的子字符串的数目(滑动窗口 双指针 哈希)

题目描述 解题思路 本题用到了滑动窗口 双指针 哈希 刚开始我是没读懂题的因为我笨 我想把我的思路说一下 左端不轻易缩小 只有找到跟word2匹配了 比如说abbcdd 遍历到c的时候才能匹配这个word2 对吧 那么之后加上以一个d或者俩d 都符合了 然后我们算完了 才能缩小左端 扩大…

python爬虫案例——异步加载网站数据抓取,post请求(6)

文章目录 前言1、任务目标2、抓取流程2.1 分析网页2.2 编写代码2.3 思路分析前言 本篇案例主要讲解异步加载网站如何分析网页接口,以及如何观察post请求URL的参数,网站数据并不难抓取,主要是将要抓取的数据接口分析清楚,才能根据需求编写想要的代码。 1、任务目标 目标网…

STM32篇:按键点亮LED灯

输入&#xff08;按键&#xff09;&#xff1a;KEY1---PA0 KEY2---PA1 输出&#xff08;LED灯&#xff09;&#xff1a;LED1---PB8 LED2---PB9

【M-LOAM学习】

M-LOAM(INITIALIZATION) Article Analysis Scan-Based Motion Estimation 通过在consecutive frame (each LiDAR)&#xff08;因为omp parallel&#xff09;中寻找correspondences然后通过最小化所有考虑feature之间residual error的transformation between frame to frame 针…

(done) 声音信号处理基础知识(7) (Understanding Time Domain Audio Features)

参考&#xff1a;https://www.youtube.com/watch?vSRrQ_v-OOSg&t1s 时域特征包括&#xff1a; 1.幅度包络 2.均方根能量 3.过零率 振幅包络的定义&#xff1a;一个 frame 里&#xff0c;所有采样点中最大的振幅值 一个形象的关于振幅包络的可视化解释如下&#xff1a;…

MateBook 16s 2023在Deepin下开启性能模式,调节风扇转速到最大,全网首发!

方法 在Deepin下按住Fnp快捷键&#xff0c;开启性能模式。 验证 首先去debian下载acpi-call-dkms https://packages.debian.org/sid/all/acpi-call-dkms/download 然后使用root用户执行&#xff1a; apt install --simulate ./acpi-call-dkms_1.2.2-2.1_all.deb apt inst…

C++入门——(类的默认成员函数)析构函数

文章目录 一、析构函数二、析构函数的特点总结 一、析构函数 析构函数与构造函数功能相反&#xff0c;析构函数不是完成对对象本⾝的销毁&#xff0c;⽐如局部对象是存在栈帧的&#xff0c;函数结束栈帧销毁&#xff0c;他就释放了&#xff0c;不需要我们管&#xff0c;C规定对…

【ChatGPT】提示词助力广告文案、PPT制作与书籍推荐的高效新模式

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;高效广告推销文案提示词使用方法 &#x1f4af;AI自动生成PPT全流程提示词使用方法 &#x1f4af;精选书籍推荐爆款文案提示词使用方法 &#x1f4af;小结 &#x1f4af;…