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

news2024/9/23 5:07:38

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;    // 推断为 boolean

let 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.coloradmin.cn/o/2156628.html

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

相关文章

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

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

【机器学习】ROC曲线

【机器学习】ROC曲线 1、ROC曲线简介2、ROC曲线和AUC值2.1 ROC曲线2.2 AUC值 3、实验内容3.1 准备数据集3.2 特征提取3.3 数据集划分3.4 模型训练与预测3.5 计算和绘制ROC曲线3.6 绘制混淆矩阵3.7 三分类混淆矩阵 4 源代码4.1 实现ROC二分类4.2 三分类混淆例子 1、ROC曲线简介 …

cnn机器学习时python版本不兼容报错

在使用python执行CNN算法时&#xff0c;发生如下报错&#xff1a; A module that was compiled using NumPy 1.x cannot be run in NumPy 2.1.1 as it may crash. To support both 1.x and 2.x versions of NumPy, modules must be compiled with NumPy 2.0. Some module may …

网络高级day03(Http)

目录 【1】HTTP简介 【2】 HTTP特点 【3】 HTTP协议格式 1》客户端请求消息格式 1> 请求行 2> 请求头 3> 空行 4> 请求数据 2》服务器响应消息格式 【1】HTTP简介 HTTP协议是Hyper Text Transfer Protocol &#xff08;超文本传输协议&#xff09;的缩写&a…

低代码平台:数据筛选功能的全新变革

随着软件开发需求的不断增长&#xff0c;传统的开发方法因其复杂性和耗时性而逐渐无法满足市场对快速交付和迭代的需求。低代码开发平台作为一种新型的软件开发工具&#xff0c;以其高效、易用的特点受到了广泛的关注和应用。 在软件开发领域&#xff0c;数据筛选是一项基础且…

frpc内网穿透

官网地址&#xff1a;frp官网 本次用到的Liunx包&#xff1a; https://github.com/fatedier/frp/releases/download/v0.60.0/frp_0.60.0_linux_amd64.tar.gz下载&#xff1a; wget https://github.com/fatedier/frp/releases/download/v0.60.0/frp_0.60.0_linux_amd64.tar.g…

经典大语言模型解读(3):参数量更大、泛化性能更强的生成式模型GPT-2

概述 在GPT-1的基础上&#xff0c;OpenAI提出了包含15亿参数&#xff08;GPT-1参数量的10倍以上&#xff09;的GPT-2模型。该模型在一个更大规模的文本数据集WebText上进行预训练。与GPT-1依赖特定任务上的有监督微调来提升性能不同&#xff0c;GPT-2具备更强的零样本&#xf…

中小企业体系技术抽象沉淀-异地灾备篇

IT团队内部使用工具 系列文章&#xff1a;https://blog.csdn.net/caicongyang/article/details/136857045 DDL DML管控 https://github.com/hhyo/Archery/ flyway 文档编写 wiki 技术对外输出文档推荐gitbook 同城双活数据同步方案 总览&#xff1a; vivo 系列文章&#x…

脱离枯燥的CRUD,灵活使用Mybatis,根据mybatis动态的xml片段和接口规范动态生成代理类,轻松应付简单业务场景。

需求 需求是这样的&#xff0c;我们有一个数据服务平台的产品&#xff0c;用户先将数据源信息保存到平台上&#xff0c;一个数据源可以提供多个接口服务&#xff0c;而每个接口服务在数据库中存一个具有mybatis语法的sql片段。这样的话&#xff0c;对于一些简单的业务只需要编…

*C++:list

一.list简介 1. list 是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list 的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个元素和后一个元素…

一文 学透 力扣—N数之和

题目一&#xff1a;1. 两数之和❤ 题目思路 当我们需要查询一个元素是否出现过&#xff0c;或者一个元素是否在集合里的时候&#xff0c;就要第一时间想到哈希法。 本题呢&#xff0c;我就需要一个集合来存放我们遍历过的元素&#xff0c;然后在遍历数组的时候去询问这个集合…

第一个NDK项目

新建项目 选择Native C的项目&#xff0c;我这里给项目的命名是NDKTest。 目录分析 新增了一个cpp目录&#xff0c;里面有一个CMakeLists和.cpp文件。 CMakeLists 文件是用来配置C编译过程的。 # Sets the minimum CMake version required for this project. cmake_minimum_…

[OpenCV] 数字图像处理 C++ 学习——16直方图均衡化、直方图比较 详细讲解+附完整代码

文章目录 前言1.直方图均衡化的理论基础(1)什么是直方图(2)直方图均衡化原理(3)直方图均衡化公式 2.直方图比较理论基础(1)相关性 (Correlation)——HISTCMP_CORREL(2)卡方 (Chi-Square)——HISTCMP_CHISQR(3)十字交叉性 (Intersection) ——HISTCMP_INTERSECT(4)巴氏距离 (Bha…

缓存的思考与总结

缓存的思考与总结 什么是缓存缓存命中率数据一致性旁路模式 Cache aside双写模式直写模式 write through异步写 Write Behind 旁路和双写 案例 新技术或中间的引入&#xff0c;一定是解决了亟待解决的问题或是显著提升了系统性能&#xff0c;并且这种改变所带来的增幅&#xff…

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

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

基于单片机的智能小车的开发与设计

摘要&#xff1a;本文论述了基于 STC89C52 单片机的智能小车的开发与设计过程。该设计采用单片机、电机驱动及光电循迹等技术&#xff0c;保证小车在无人管理状态下&#xff0c;能按照预先设定的线路实现自动循迹功能。在电路结构设计中力求方便&#xff0c;可操作&#xff0c;…

go webapi上传文件

一、导入依赖 import "net/http" 我这里用到了Guid所以安装依赖 go get github.com/google/uuid 二、main.go package mainimport ("fmt""github.com/jmoiron/sqlx""github.com/tealeg/xlsx""log""path/filepath&q…

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

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

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

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

计算机组成原理——存储系统

计算机组成原理——存储系统 存储器层次结构 存储器层次结构如下&#xff1a; 寄存器&#xff08;CPU&#xff09;Cache&#xff08;高速缓冲存储器&#xff09;主存磁盘磁带、光盘等 按照上述层次结构&#xff0c;自下而上速度依次增快、容量相对依次渐小、造价越来越高昂…