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

Typescript学习教程,从入门到精通,TypeScript 进阶语法知识点及案例代码详解(13)

TypeScript 进阶语法知识点及案例代码详解

本文将详细介绍 TypeScript 中关于类型兼容、类型操作、异步处理等核心概念,并结合具体案例代码进行深入解析。

1.1 接口兼容性(Interface Compatibility)

语法知识点:

  • 结构化类型系统(Structural Typing):TypeScript 使用结构化类型系统,即只要两个类型的结构一致,它们就是兼容的,而不考虑它们的具体名称。
  • 可选属性与额外属性:接口兼容性允许目标类型拥有源类型中不存在的属性,但源类型必须包含目标类型的所有必需属性。

案例代码:

// 定义两个接口
interface Person {name: string;age: number;
}interface Employee {name: string;age: number;department: string;
}// 函数接受 Person 类型参数
function greet(person: Person) {console.log(`Hello, ${person.name}`);
}// 创建一个 Employee 类型的对象
const employee: Employee = {name: "Alice",age: 30,department: "Engineering"
};// 将 Employee 类型的对象传递给接受 Person 类型参数的函数
greet(employee); // 合法,因为 Employee 包含 Person 的所有必需属性

解释:

  • Employee 接口包含 Person 接口的所有属性,并且有额外的 department 属性。
  • 由于 TypeScript 的结构化类型系统,Employee 类型的对象可以赋值给 Person 类型的参数,因为 Employee 包含 Person 的所有必需属性。

1.2 类兼容性(Class Compatibility)

语法知识点:

  • 类的实例兼容性:类的实例兼容性主要基于其公共属性和方法,私有和受保护的成员不影响兼容性。
  • 构造函数:类的构造函数不参与兼容性检查。

案例代码:

class Animal {public name: string;constructor(name: string) {this.name = name;}
}class Dog {public name: string;public breed: string;constructor(name: string, breed: string) {this.name = name;this.breed = breed;}
}let animal: Animal = new Dog("Buddy", "Golden Retriever"); // 合法,因为 Dog 包含 Animal 的所有公共属性

解释:

  • Dog 类包含 Animal 类的所有公共属性 (name),因此 Dog 类型的实例可以赋值给 Animal 类型的变量。
  • 额外的 breed 属性不影响兼容性。

1.3 函数兼容性(Function Compatibility)

语法知识点:

  • 参数兼容性:目标函数的参数类型必须与源函数的参数类型兼容(目标函数可以有更多参数,但必须包含源函数的所有必需参数)。
  • 返回类型兼容性:源函数的返回类型必须与目标函数的返回类型兼容。

案例代码:

// 定义两个函数类型
type GreetFunction = (name: string) => void;
type LogFunction = (message: string, level?: string) => void;// 实现函数
const greet: GreetFunction = (name) => {console.log(`Hello, ${name}`);
};const log: LogFunction = (message, level = "INFO") => {console.log(`${level}: ${message}`);
};// 函数赋值
let func1: GreetFunction = log; // 合法,因为 LogFunction 的参数兼容 GreetFunction
let func2: LogFunction = greet; // 不合法,因为 GreetFunction 的参数不包含 LogFunction 的第二个参数

解释:

  • func1 的赋值是合法的,因为 LogFunction 的参数列表可以兼容 GreetFunction(即可以接受一个 string 类型的参数)。
  • func2 的赋值是不合法的,因为 GreetFunction 不包含 LogFunction 的第二个可选参数。

2. 类型操作(Type Operations)

2.1 联合类型(Union Types)

语法知识点:

  • 联合类型:表示一个值可以是几种类型之一,使用 | 分隔。
  • 类型保护:使用类型断言或类型守卫来缩小联合类型的范围。

案例代码:

// 定义联合类型
type StringOrNumber = string | number;// 函数接受联合类型参数
function printValue(value: StringOrNumber) {if (typeof value === "string") {console.log(`String: ${value}`);} else if (typeof value === "number") {console.log(`Number: ${value}`);} else {// 永远不会发生,因为已经覆盖了所有可能的类型const _exhaustiveCheck: never = value;throw new Error(`Unhandled type: ${typeof value}`);}
}printValue("Hello"); // 输出: String: Hello
printValue(42);       // 输出: Number: 42

解释:

  • StringOrNumber 是一个联合类型,可以是 stringnumber
  • printValue 函数中,使用 typeof 操作符进行类型保护,以确定 value 的具体类型。

2.2 交叉类型(Intersection Types)

语法知识点:

  • 交叉类型:表示一个值同时具有几种类型的特性,使用 & 分隔。
  • 组合类型:常用于组合多个对象的属性。

案例代码:

// 定义两个接口
interface Person {name: string;age: number;
}interface Employee {employeeId: number;department: string;
}// 定义交叉类型
type PersonEmployee = Person & Employee;// 创建对象
const personEmployee: PersonEmployee = {name: "Alice",age: 30,employeeId: 123,department: "Engineering"
};// 使用对象
console.log(personEmployee.name);       // 输出: Alice
console.log(personEmployee.employeeId); // 输出: 123

解释:

  • PersonEmployee 是一个交叉类型,包含了 PersonEmployee 接口的所有属性。
  • personEmployee 对象必须同时满足 PersonEmployee 的所有要求。

2.3 类型别名(Type Aliases)

语法知识点:

  • 类型别名:为现有类型创建一个新名称,使用 type 关键字。
  • 可重用性:提高代码的可读性和可维护性。

案例代码:

// 定义类型别名
type StringOrNumber = string | number;
type Coordinates = { x: number; y: number; };// 使用类型别名
function add(a: StringOrNumber, b: StringOrNumber): StringOrNumber {if (typeof a === "number" && typeof b === "number") {return a + b;}if (typeof a === "string" && typeof b === "string") {return a + b;}throw new Error("Invalid arguments");
}const position: Coordinates = { x: 10, y: 20 };

解释:

  • StringOrNumberstringnumber 的联合类型。
  • Coordinates 是包含 xy 属性的对象类型。
  • 使用类型别名可以使代码更加简洁和易于理解。

2.4 类型推断(Type Inference)

语法知识点:

  • 类型推断:TypeScript 自动推断变量的类型,无需显式声明。
  • 最佳通用类型:推断出的类型是所有可能类型的最佳通用类型。

案例代码:

// 推断为 number 类型
let num = 42;// 推断为 string 类型
let str = "Hello";// 推断为 (a: number, b: number) => number 类型
let add = (a: number, b: number) => a + b;// 推断为 Array<string> 类型
let fruits = ["Apple", "Banana", "Cherry"];// 推断为 { name: string; age: number; } 类型
let person = {name: "Alice",age: 30
};

解释:

  • TypeScript 根据初始化值的类型自动推断变量的类型。
  • add 函数中,返回类型也被推断为 number

2.5 类型断言(Type Assertions)

语法知识点:

  • 类型断言:告诉编译器某个值的具体类型,使用 as 关键字或尖括号语法。
  • 谨慎使用:避免不安全地断言不正确的类型。

案例代码:

// 使用 as 关键字进行类型断言
let someValue: any = "this is a string";// 断言为 string 类型
let strLength: number = (someValue as string).length;// 使用尖括号语法进行类型断言
let strLength2: number = (<string>someValue).length;// 谨慎使用类型断言
function getLength(value: string | number): number {// 错误示例:断言为 string,但 value 也可能是 number// return (value as string).length;// 正确示例:使用类型保护if (typeof value === "string") {return value.length;}return 0;
}

解释:

  • someValue 被断言为 string 类型,以便访问 length 属性。
  • getLength 函数中,不能直接断言 valuestring,因为它也可能是 number。应使用类型保护来安全地处理。

2.6 泛型(Generics)

语法知识点:

  • 泛型:在定义函数、接口或类时,不预先指定具体的类型,而是在使用时指定类型。
  • 类型参数:使用 <T> 来定义类型参数。

案例代码:

// 定义泛型函数
function identity<T>(arg: T): T {return arg;
}// 使用泛型函数
let num = identity<number>(42);
let str = identity<string>("Hello");// 类型推断也可以省略类型参数
let num2 = identity(42);
let str2 = identity("Hello");// 定义泛型接口
interface Box<T> {value: T;
}// 使用泛型接口
let boxNumber: Box<number> = { value: 100 };
let boxString: Box<string> = { value: "Box" };

解释:

  • identity 函数是一个泛型函数,可以接受任何类型的参数,并返回相同类型的值。
  • 使用泛型可以提高代码的复用性和灵活性。
  • Box 接口是一个泛型接口,可以容纳任何类型的值。

3. 错误处理(Error Handling)

3.1 传统回调函数实现异步处理(Traditional Callback Functions)

语法知识点:

  • 回调函数:在异步操作完成后调用的函数。
  • 错误优先回调:回调函数的第一个参数通常用于传递错误信息。

案例代码:

// 模拟异步操作
function fetchData(callback: (error: string | null, data: string | null) => void) {setTimeout(() => {const success = true; // 模拟成功或失败if (success) {callback(null, "Data fetched successfully");} else {callback("Error fetching data", null);}}, 1000);
}// 使用回调函数处理异步操作
fetchData((error, data) => {if (error) {console.error(`Error: ${error}`);} else {console.log(`Success: ${data}`);}
});

解释:

  • fetchData 函数模拟一个异步操作,使用回调函数来处理结果。
  • 回调函数的第一个参数用于传递错误信息,第二个参数用于传递成功的数据。

3.2 Promise 实现异步编程(Promise-Based Asynchronous Programming)

语法知识点:

  • Promise:表示一个异步操作的最终完成或失败及其结果值。
  • 链式调用:使用 .then().catch() 进行链式调用。
  • Promise 状态:pending、fulfilled、rejected。

案例代码:

// 模拟异步操作
function fetchData(): Promise<string> {return new Promise((resolve, reject) => {setTimeout(() => {const success = true; // 模拟成功或失败if (success) {resolve("Data fetched successfully");} else {reject("Error fetching data");}}, 1000);});
}// 使用 Promise 处理异步操作
fetchData().then((data) => {console.log(`Success: ${data}`);}).catch((error) => {console.error(`Error: ${error}`);});

解释:

  • fetchData 函数返回一个 Promise 对象,表示一个异步操作。
  • 使用 .then() 处理成功的结果,使用 .catch() 处理错误。

3.3 async 和 await(Async and Await)

语法知识点:

  • async 函数:声明一个异步函数,返回一个 Promise。
  • await 表达式:等待一个 Promise 解决,并返回其结果。
  • 错误处理:使用 try-catch 语句进行错误处理。

案例代码:

// 模拟异步操作
function fetchData(): Promise<string> {return new Promise((resolve, reject) => {setTimeout(() => {const success = true; // 模拟成功或失败if (success) {resolve("Data fetched successfully");} else {reject("Error fetching data");}}, 1000);});
}// 使用 async 和 await 处理异步操作
async function getData() {try {const data = await fetchData();console.log(`Success: ${data}`);} catch (error) {console.error(`Error: ${error}`);}
}getData();

解释:

  • getData 是一个 async 函数,使用 await 等待 fetchData 函数的 Promise 解决。
  • 使用 try-catch 语句来处理可能的错误。

4. 综合案例代码(Comprehensive Example)

以下是一个综合运用上述知识点的案例代码,展示了如何使用泛型、类型别名、错误处理和 async/await 来实现一个简单的数据获取函数。

// 定义类型别名
type FetchResult<T> = { data: T; error: string | null; };// 定义泛型函数
async function fetchData<T>(url: string): Promise<FetchResult<T>> {try {const response = await fetch(url);if (!response.ok) {return { data: null, error: `HTTP error! status: ${response.status}` };}const result: T = await response.json();return { data: result, error: null };} catch (error) {return { data: null, error: `Error: ${error}` };}
}// 使用 async 函数调用 fetchData
async function getUserData() {const url = "https://api.example.com/user/1";const result = await fetchData<{ id: number; name: string; age: number; }>(url);if (result.error) {console.error(result.error);} else {console.log(`User ID: ${result.data.id}, Name: ${result.data.name}, Age: ${result.data.age}`);}
}getUserData();

解释:

  1. 类型别名FetchResult<T> 是一个类型别名,表示一个包含 dataerror 属性的对象,data 的类型由泛型参数 T 决定。
  2. 泛型函数fetchData 是一个泛型函数,接受一个 URL 和一个类型参数 T,返回一个 Promise<FetchResult<T>>
  3. 错误处理:在 fetchData 中,使用 try-catch 语句来捕获网络错误,并在返回结果中包含错误信息。
  4. async/awaitgetUserData 是一个 async 函数,使用 await 来调用 fetchData 并处理结果。
  5. 调用示例:调用 getUserData 来获取用户数据,并打印出来。

总结

本文详细介绍了 TypeScript 中关于类型兼容、类型操作、错误处理和异步处理的核心概念,并通过具体的案例代码进行了深入解析。通过掌握这些高级特性,您可以编写出更加健壮、可维护和高效的 TypeScript 代码。

http://www.xdnf.cn/news/642583.html

相关文章:

  • QStandardItemModel的函数和信号介绍
  • Java单例模式:懒汉模式详解
  • MyBatis-Plus一站式增强组件MyBatis-Plus-kit:打造更优雅的通用CRUD解决方案
  • 15 dart类(get,set,静态,继承,抽象,接口,混入)
  • AUTOSAR图解==>AUTOSAR_SRS_Libraries
  • java数组,ArrayList,LinkedList
  • win主机,Ubuntu,IMX6ULL开发板网络通讯
  • 神经网络学习-Day35
  • 麒麟V10 SP1 2303使用记录(一)安装google浏览器
  • 提高:RMQ问题:【例 3】与众不同
  • 固态硬盘颗粒类型、选型与应用场景深度解析
  • 基于PySide6与pycatia的CATIA几何阵列生成器开发实践
  • 5.25 note
  • uni-app学习笔记十二-vue3中创建组件
  • ISO 20000体系:需求管理与容量管理含义与解释
  • 以下是修改Java版《我的世界》字体的分步指南(DeepSeek)
  • uni-app学习笔记十一--vu3 watch和watchEffect侦听
  • IntelliJ IDEA 中配置 Gradle 的分发方式distribution
  • jvm垃圾回收
  • github项目:llm-guard
  • 函数[x]和{x}在数论中的应用
  • 李沐《动手学深度学习》| 4.4 模型的选择、过拟合和欠拟合.md
  • STL的map和set(关联式容器深度解析)
  • 2025第三届黄河流域网络安全技能挑战赛--Crypto--WriteUp
  • 网络原理入门详解:从零理解互联网如何工作
  • Modbus协议原理
  • 【Hive 开发进阶】窗口函数深度解析:OVER/NTILE/RANK 实战案例与行转列高级技巧
  • Day02
  • springboot日志
  • NotePad++编辑Linux服务器文档