7.5 TypeScript语言参考手册
1. Hello World
下面是一个基本的 TypeScript 入门指南:
-
TypeScript 是什么?
- TypeScript 是 JavaScript 的超集,它在 JavaScript 的基础上增加了静态类型检查和其他编译时功能。
- TypeScript 通过添加类型注解和接口等功能来提供更好的可读性、可维护性和代码提示。
-
安装 TypeScript 编译器:
- 首先,你需要安装 TypeScript 编译器。你可以使用 npm(Node Package Manager)来进行安装:
$ npm install -g typescript
- 首先,你需要安装 TypeScript 编译器。你可以使用 npm(Node Package Manager)来进行安装:
-
创建 TypeScript 文件:
- 创建一个新的
.ts
或.tsx
扩展名的 TypeScript 文件,例如app.ts
。
-
TypeScript 基本语法:
- TypeScript 可以识别大部分 JavaScript 代码,但还具有一些额外的语法和功能。
- 类型注解:使用冒号
:
来为变量、函数参数和函数返回值等添加类型注解。 - 类型推断:TypeScript 可以根据上下文自动推断变量的类型,省略类型注解。
- 接口:使用
interface
关键字来定义对象的结构和属性。 - 类:使用
class
关键字创建类,并使用constructor
方法来初始化对象。 - 模块/命名空间:使用
import
和export
关键字来模块化你的代码。 - 泛型:使用
<T>
来创建可重用、灵活的组件。 - 枚举:使用
enum
关键字来定义一组命名的常量。
-
编译 TypeScript 文件:
- 在终端中,运行以下命令来编译 TypeScript 文件:
$ tsc app.ts
- 这将生成一个 JavaScript 文件
app.js
。
- 在终端中,运行以下命令来编译 TypeScript 文件:
-
运行 TypeScript 文件:
- 你可以使用 Node.js 运行已经编译的 JavaScript 文件:
$ node app.js
- 你可以使用 Node.js 运行已经编译的 JavaScript 文件:
下面是一个简单的 TypeScript “Hello, World!” 的示例:
// 创建一个函数,用于打印 Hello, World!
function sayHello() {
console.log("Hello, World!");
}
// 调用函数
sayHello();
在上述示例中,我们首先创建了一个名为 sayHello
的函数,它负责打印 “Hello, World!"。然后,我们通过调用 sayHello()
函数来触发打印操作。
要运行 TypeScript 代码,你需要将其编译为 JavaScript。下面是在终端中使用 TypeScript 编译器编译上述代码的步骤:
- 将上述代码保存为
hello.ts
文件。 - 打开终端,并导航到包含
hello.ts
文件的目录。 - 运行以下命令来编译 TypeScript 文件:
这将生成一个 JavaScript 文件$ tsc hello.ts
hello.js
。 - 最后,在终端中运行以下命令来执行 JavaScript 文件:
$ node hello.js
执行以上步骤后,你应该在终端中看到输出的 “Hello, World!"。这就是一个简单的 TypeScript “Hello, World!” 示例!
2. 变量
在 TypeScript 中,变量可以通过关键字 let
和 const
来声明。这两个关键字用于声明具有不同特性的变量。
-
let
:- 使用
let
关键字声明的变量是可变的(mutable),即其值可以被重新分配。 - 变量在声明后可以被更新和重新赋值。
- 示例:
let message: string = "Hello"; message = "World";
- 使用
-
const
:- 使用
const
关键字声明的变量是不可变的(immutable),即其值在声明后不能被更改。 const
声明的变量必须在声明时进行初始化,并且不能再次赋值。- 示例:
const PI: number = 3.14159; const person = { name: "John", age: 30 }; person.age = 31; // 可以修改 person 对象的属性,但不能重新分配 person 变量
- 使用
-
类型注解:
- 在 TypeScript 中,变量可以使用类型注解来指定其类型。
- 类型注解可以在变量名后使用冒号
:
指定类型。 - TypeScript 提供了许多内置类型,如
number
、string
、boolean
、object
等,也可以使用自定义类型。 - 示例:
let count: number = 10; let name: string = "John"; let isDone: boolean = false; let person: { name: string, age: number } = { name: "John", age: 30 };
-
类型推断:
- TypeScript 可以根据变量的初始化值自动推断其类型,无需显式指定。
- 示例:
let message = "Hello"; // 推断为 string 类型 let age = 30; // 推断为 number 类型 let isActive = true; // 推断为 boolean 类型
总结:
- 使用
let
声明可变的变量,可以进行重新赋值。 - 使用
const
声明不可变的常量,必须进行初始化,并且不能重新赋值。 - 可以使用类型注解指定变量的类型,也可以让 TypeScript 根据初始化值自动推断类型。
在 TypeScript 中,变量可以具有多种类型。以下是 TypeScript 中常用的变量类型:
-
基本类型:
number
:表示数字类型,例如:let age: number = 30;
string
:表示字符串类型,例如:let name: string = "John";
boolean
:表示布尔类型,例如:let isActive: boolean = true;
null
:表示空值类型,例如:let value: null = null;
undefined
:表示未定义类型,例如:let message: undefined = undefined;
symbol
:表示唯一标识符类型,例如:let id: symbol = Symbol("id");
-
复杂类型:
array
:表示数组类型,例如:let numbers: number[] = [1, 2, 3, 4, 5]; let names: string[] = ["John", "Jane", "Joe"];
tuple
:表示元组类型,即具有固定数量和特定类型的元素数组,例如:let person: [string, number] = ["John", 30];
object
:表示对象类型,例如:let person: { name: string, age: number } = { name: "John", age: 30 };
enum
:表示枚举类型,用于定义一组命名的常量,例如:enum Color { Red, Green, Blue } let color: Color = Color.Red;
any
:表示任意类型,变量可以具有任意类型的值,例如:let data: any = "Hello";
unknown
:表示未知类型,与any
类型相似,但更加类型安全,需要进行类型检查或类型断言,例如:let data: unknown = "Hello"; if (typeof data === "string") { let message: string = data; // 进行类型检查后赋值 }
void
:表示空类型,函数没有返回值时使用,例如:function sayHello(): void { console.log("Hello"); }
这些是 TypeScript 中常用的变量类型。通过指定适当的类型,可以提高代码的可读性和可维护性,并在开发过程中捕获潜在的错误。根据具体的需求选择合适的变量类型即可。
3. 条件分支
在 TypeScript 中,你可以使用条件分支结构来根据不同的条件执行不同的代码段。以下是常用的条件分支结构示例:
-
if
语句:if
语句用于在满足条件时执行特定的代码块。它的基本语法如下:if (condition) { // 当条件为真时执行的代码块 } else { // 当条件为假时执行的代码块(可选) }
-
if-else if-else
语句:if-else if-else
语句可以用于依次检查多个条件并执行相应的代码块。它的基本语法如下:if (condition1) { // 当条件1为真时执行的代码块 } else if (condition2) { // 当条件2为真时执行的代码块 } else { // 当以上条件都不满足时执行的代码块(可选) }
-
switch
语句:switch
语句根据给定的表达式的结果执行不同的代码块。每个case
表达式需要与给定表达式的值进行匹配。它的基本语法如下:switch (expression) { case value1: // 当 expression 等于 value1 时执行的代码块 break; case value2: // 当 expression 等于 value2 时执行的代码块 break; default: // 当 expression 不满足以上所有情况时执行的代码块(可选) break; }
在条件分支结构中,你可以通过逻辑运算符(如 &&
、||
)和比较运算符(如 ===
、!==
)来构建条件表达式。条件表达式的结果应该是布尔值 true
或 false
。
以下是一个使用条件分支的 TypeScript 示例,用于判断一个数字是否为正数、负数或零:
function checkNumber(num: number): void {
if (num > 0) {
console.log("Positive number");
} else if (num < 0) {
console.log("Negative number");
} else {
console.log("Zero");
}
}
checkNumber(5); // 输出:Positive number
checkNumber(-2); // 输出:Negative number
checkNumber(0); // 输出:Zero
在这个示例中,我们定义了一个 checkNumber
函数,它根据传入的数字参数进行条件检查,并输出相应的结果。
4. 循环
在 TypeScript 中,你可以使用循环结构来重复执行一段代码。以下是常用的循环结构:
-
for
循环: 使用for
循环来迭代一个定义好的计数器,执行指定的代码块。它的基本语法如下:for (initialization; condition; increment) { // 在每次迭代时执行的代码块 }
其中:
initialization
:初始化计数器的值。condition
:迭代条件,当条件为真时,继续迭代;当条件为假时,退出循环。increment
:每次迭代后对计数器进行的操作,例如递增或递减计数器的值。
示例:
for (let i = 0; i < 5; i++) { console.log(i); }
-
while
循环: 使用while
循环在满足条件时重复执行一段代码。它的基本语法如下:while (condition) { // 当条件为真时重复执行的代码块 }
其中:
condition
:循环条件,当条件为真时,继续循环;当条件为假时,退出循环。
示例:
let i = 0; while (i < 5) { console.log(i); i++; }
-
do-while
循环: 使用do-while
循环在执行一段代码后检查条件,如果条件满足,则重复执行。它的基本语法如下:do { // 先执行一次的代码块 } while (condition);
其中:
condition
:循环条件,当条件为真时,继续循环;当条件为假时,退出循环。
示例:
let i = 0; do { console.log(i); i++; } while (i < 5);
这些是 TypeScript 中常用的循环结构。使用循环可以在处理重复性任务时简化代码并提高效率。你可以根据具体的需求选择合适的循环结构。
需要注意的是,在使用循环时,确保提供适当的终止条件,以避免无限循环。另外,你还可以使用 break
和 continue
关键字来控制循环的执行流程。
在 TypeScript(以及 JavaScript)中,forEach
是一个数组方法,用于迭代数组的每个元素并对其执行回调函数。forEach
方法可以简化对数组进行循环的代码。以下是 forEach
方法的基本语法和示例:
array.forEach(callback: (value: T, index: number, array: T[]) => void): void
array
:要迭代的数组。callback
:在每个数组元素上执行的回调函数,它可以接受三个参数:value
:当前迭代的数组元素的值。index
:当前迭代的数组元素的索引。array
:调用forEach
方法的数组对象本身。
void
:forEach
方法没有返回值。
示例代码:
const numbers: number[] = [1, 2, 3, 4, 5];
numbers.forEach((value, index, array) => {
console.log(`Value: ${value}, Index: ${index}, Array: ${array}`);
});
在上面的示例中,我们定义了一个名为 numbers
的数组。然后使用 forEach
方法迭代数组中的每个元素,对每个元素执行回调函数,该回调函数将打印当前元素的值、索引和数组本身。
值得注意的是,forEach
方法仅用于循环遍历数组,并且不能在循环中使用 break
或 continue
来控制循环流程。如果需要在遍历数组时进行条件判断或中断循环,可以选择使用 for
循环或 for...of
循环。
5. 函数
在 TypeScript 中,你可以使用 function
关键字来定义函数,函数是一段可重复使用的代码块,用于执行特定任务或计算结果。以下是 TypeScript 中函数的基本语法和示例:
-
基本函数定义:
function functionName(parameter1: type, parameter2: type, ...): returnType { // 函数体,包含要执行的代码 return result; // 返回值(可选) }
functionName
:函数名称,用于唯一标识函数。parameter1
,parameter2
, …:函数的参数,用于接受传入函数的值。每个参数都需要指定类型。type
:参数的类型,用于指定参数所接受的值的类型。returnType
:函数的返回值类型,用于指定函数执行完毕后返回的数据类型。如果函数没有返回值,可以使用void
。
示例:
function add(a: number, b: number): number { return a + b; } const result = add(3, 5); // 调用 add 函数 console.log(result); // 输出:8
-
可选参数和默认参数: TypeScript 支持可选参数和默认参数。
-
可选参数: 可选参数用
?
标记,在参数列表中,可选参数必须位于必填参数之后。可选参数允许你在调用函数时不传递该参数的值,并且在函数内部使用默认值。function sayHello(name: string, age?: number): void { console.log(`Hello, ${name}!${age ? ` You are ${age} years old.` : ""}`); } sayHello("John"); // 输出:Hello, John! sayHello("Jane", 25); // 输出:Hello, Jane! You are 25 years old.
-
默认参数: 默认参数允许你为参数提供默认值,在调用函数时,如果未显式传递该参数的值,将使用默认值。
function sayHello(name: string, age: number = 30): void { console.log(`Hello, ${name}! You are ${age} years old.`); } sayHello("John"); // 输出:Hello, John! You are 30 years old. sayHello("Jane", 25); // 输出:Hello, Jane! You are 25 years old.
-
-
剩余参数: 使用剩余参数可以将多个参数收集到一个数组中。剩余参数在函数定义时以
...
开头,可以接受任意数量的参数,并将它们作为数组传递给函数内部使用。function sum(...numbers: number[]): number { let total = 0; for (let num of numbers) { total += num; } return total; } const result = sum(1, 2, 3, 4, 5); // 调用 sum 函数 console.log(result); // 输出:15
这些是 TypeScript 中函数的基本用法。函数将一段代码封装成可重复使用的块,并提供输入和输出。你可以根据需要定义函数,并使用相应的参数、返回值类型和修饰符来满足需求。
6. 包
在 TypeScript 中,你可以使用各种包(Packages)来扩展和组织你的代码。以下是一些常见的 TypeScript 包和库:
-
lodash: lodash 是一个实用工具库,提供了许多用于简化 JavaScript 编程的功能,如集合操作、数组操作、函数式编程等。
安装方式:
npm install lodash
示例用法:
import * as _ from 'lodash'; const numbers = [1, 2, 3, 4, 5]; const sum = _.sum(numbers); console.log(sum); // 输出:15
-
axios: axios 是一个基于 Promise 的 HTTP 客户端,用于发送 HTTP 请求并处理响应。
安装方式:
npm install axios
示例用法:
import axios from 'axios'; axios.get('https://api.example.com/data') .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });
-
React: React 是一个流行的 JavaScript 库,用于构建用户界面。
安装方式:
npm install react react-dom
示例用法:
import React from 'react'; import ReactDOM from 'react-dom'; const App = () => { return <h1>Hello, React!</h1>; }; ReactDOM.render(<App />, document.getElementById('root'));
-
Express: Express 是一个流行的 Web 应用程序框架,用于构建服务器端应用程序。
安装方式:
npm install express
示例用法:
import express from 'express'; const app = express(); app.get('/', (req, res) => { res.send('Hello, Express!'); }); app.listen(3000, () => { console.log('Server started on port 3000'); });
这些只是 TypeScript 中可用的一小部分包和库的示例。根据你的应用需求,可能会使用其他不同的包和库。
要使用这些包,你需要将它们作为依赖项添加到项目的 package.json
文件中,然后使用包管理器(如 npm 或 yarn)进行安装。
7. 数组
在 TypeScript 中,数组(Array)是一种用于存储多个值的有序集合。数组可以包含相同类型的元素,也可以包含不同类型的元素。以下是 TypeScript 中数组的一些常见操作和属性:
-
声明数组: 可以使用以下两种方式声明一个数组:
let array1: number[] = [1, 2, 3]; // 数字类型数组 let array2: string[] = ['Hello', 'World']; // 字符串类型数组
-
泛型数组类型: 可以使用
Array<类型>
或类型[]
的形式来声明数组:let array: Array<number> = [1, 2, 3]; // 数字类型数组 let list: string[] = ['Hello', 'World']; // 字符串类型数组
-
访问数组中的元素: 使用索引来访问数组中的元素,索引从 0 开始:
let numbers: number[] = [1, 2, 3]; console.log(numbers[0]); // 输出:1
-
修改数组中的元素: 数组的元素是可变的,可以通过索引修改数组中的元素:
let numbers: number[] = [1, 2, 3]; numbers[1] = 5; console.log(numbers); // 输出:[1, 5, 3]
-
数组长度(length): 可以使用
length
属性获取数组的长度,即数组中元素的个数:let numbers: number[] = [1, 2, 3]; console.log(numbers.length); // 输出:3
-
数组方法: TypeScript/JavaScript 提供了许多用于操作数组的内置方法,如
push()
、pop()
、shift()
、unshift()
、slice()
、splice()
等。这些方法可以帮助你添加、删除、修改或获取数组中的元素。示例:
let numbers: number[] = [1, 2, 3]; numbers.push(4); // 在数组末尾添加一个元素 console.log(numbers); // 输出:[1, 2, 3, 4] numbers.pop(); // 删除数组末尾的元素 console.log(numbers); // 输出:[1, 2, 3] numbers.shift(); // 删除数组开头的元素 console.log(numbers); // 输出:[2, 3] numbers.unshift(0); // 在数组开头添加一个元素 console.log(numbers); // 输出:[0, 2, 3] let slicedArray = numbers.slice(1, 2); // 截取数组的一部分 console.log(slicedArray); // 输出:[2] numbers.splice(1, 1, 4, 5); // 在索引位置 1 删除一个元素,并插入 4 和 5 console.log(numbers); // 输出:[0, 4, 5, 3]
这些是 TypeScript 中数组的一些基本操作和属性。数组是一种非常常用的数据结构,可用于存储和操作多个值。通过了解这些操作和属性,你可以更好地使用和处理数组。
8. Map
在 TypeScript 中,map
是一种数据类型,它表示键值对的集合,其中每个键都是唯一的,可以用来快速查找和访问值。
Map<K, V>
是 TypeScript 中的内置类型,其中 K
表示键的类型,V
表示值的类型。可以使用 new Map()
构造函数来创建一个空的 Map
对象,或者使用 Map
构造函数的参数来初始化一个带有初始键值对的 Map
对象。
以下是使用 Map
类型的示例:
let map: Map<string, number> = new Map();
// 使用 set() 方法向 Map 添加键值对
map.set("apple", 5);
map.set("banana", 10);
map.set("orange", 8);
// 使用 get() 方法获取指定键的值
let appleCount = map.get("apple"); // 返回 5
let orangeCount = map.get("orange"); // 返回 8
// 使用 has() 方法检查是否存在指定的键
let hasApple = map.has("apple"); // 返回 true
let hasGrape = map.has("grape"); // 返回 false
// 使用 delete() 方法删除指定键及其对应的值
map.delete("banana");
// 遍历 Map 的键和值
map.forEach((value, key) => {
console.log(key, value);
});
// 清空 Map
map.clear();
在上述示例中,我们创建了一个名为 map
的 Map
对象,并使用 set()
方法向其添加了几个键值对。然后,使用 get()
方法获取键的值,并使用 has()
方法检查指定键是否存在。使用 delete()
方法删除了一个键值对,使用 forEach()
方法遍历了 Map
的键和值。最后,使用 clear()
方法清空了 Map
。
请注意,Map
中的键和值可以是任何类型,不仅限于字符串和数字。你可以根据实际需要来选择合适的类型。
9. 指针
在 TypeScript 中,与传统的编程语言(如 C 或 C++)不同,它没有直接的指针概念。TypeScript 是一种静态类型的脚本语言,它在编译时进行类型检查,并提供了类型注解和类型推断来帮助开发人员进行更安全和可靠的编码。
在 TypeScript 中,你可以声明变量并指定其类型,然后在运行时将值赋给该变量。通过使用类型注解,TypeScript 可以在编译时检查变量的类型是否与声明的类型一致。这提供了一种类型安全的方式来操作数据,从而减少了指针操作常见的错误(例如空指针访问)。
以下是一个简单的 TypeScript 示例:
let data: string = "Hello, TypeScript!";
console.log(data); // 输出: Hello, TypeScript!
在上述示例中,我们声明了一个名为 data
的变量,并将其类型指定为字符串类型。然后,我们将字符串值赋给该变量,并使用 console.log()
打印出变量的值。
需要注意的是,TypeScript 并不会将变量存储在内存中的特定位置,也不会进行手动内存管理。它是 JavaScript 的超集,运行在 JavaScript 的运行时环境中。
总结起来,TypeScript 没有像传统编程语言那样的直接指针概念,而是通过类型系统和类型安全的编程方式提供了更可靠和方便的数据操作。
10. 闭包
闭包是指一个函数能够记住并访问其定义时的词法作用域,即使函数是在其词法作用域之外执行的。这个特性在 TypeScript 中同样存在。
闭包的常见用途之一是创建私有变量和函数。通过使用闭包,可以在函数内部定义变量或函数,并且它们在函数执行完毕后依然可以访问和使用。这样可以有效地隐藏变量和函数,防止外部访问和修改。
以下是一个 TypeScript 中使用闭包的示例:
function createCounter() {
let count = 0;
function increment() {
count++;
console.log(count);
}
return increment;
}
let counter = createCounter();
counter(); // 输出: 1
counter(); // 输出: 2
在上述示例中,createCounter()
函数定义了一个局部变量 count
和一个返回该变量的内部函数 increment()
。 increment()
函数能够通过闭包访问并修改 count
变量的值。我们调用 createCounter()
函数并将返回的 increment
函数赋给变量 counter
,然后连续调用 counter()
函数时,每次都会增加 count
的值并打印出来。
通过使用闭包,我们可以创建一个私有的计数器,其状态被封装在闭包内部,并且无法从外部直接访问或修改。
需要注意的是,闭包可以引用外部函数中的变量和参数,而这些变量和参数在外部函数执行完毕后不会被销毁。因此,闭包可能会导致内存泄漏问题,如果闭包引用了大量的资源或者被长时间保持引用,可能会导致不必要的内存占用。
当我们在 TypeScript 中使用闭包时,可以根据具体的应用场景来展示其特点和用法。下面我会举几个例子,详细讲解 TypeScript 中的闭包。
- 私有变量: 在 TypeScript 中,我们可以利用闭包来创建私有变量,这样就可以隐藏变量并防止外部直接访问或修改。例如:
function createCounter() {
let count = 0;
function increment() {
count++;
console.log(count);
}
function decrement() {
count--;
console.log(count);
}
return { increment, decrement };
}
let counter = createCounter();
counter.increment(); // 输出: 1
counter.increment(); // 输出: 2
counter.decrement(); // 输出: 1
在上述示例中,createCounter()
函数返回一个包含 increment
和 decrement
函数的对象。这两个函数都可以访问 createCounter()
函数内部的私有变量 count
。由于闭包的存在,increment
和 decrement
函数保留了对 count
变量的引用,并且在每次调用时可以修改并访问它。
- 延长变量生命周期: 闭包还可以用于延长变量的生命周期,确保变量在外部函数执行完后仍然可用。例如:
function outerFunction() {
let name = "John";
setTimeout(function () {
console.log("Hello, " + name);
}, 2000);
}
outerFunction(); // 2秒后输出: Hello, John
在上述示例中,outerFunction
函数内部有一个 setTimeout
函数,它延迟2秒钟执行,并且内部函数仍然可以访问 outerFunction
中的 name
变量。这是因为闭包使得内部函数在执行时仍然保留了对外部函数的引用,因此可以访问外部函数中的变量。
- 循环中的闭包问题: 在使用循环时,我们需要特别注意闭包问题。在循环中创建闭包时,由于函数共享了相同的作用域,可能会导致意料之外的结果。例如:
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, i * 1000);
}
在上述示例中,我们尝试使用 setTimeout
在每秒输出计数器 i
的值。但是,由于循环结束后内部函数才执行,而这时的 i
值已经是 6
。为了解决这个问题,我们可以使用闭包来创建一个独立的作用域,从而避免共享变量。例如:
for (var i = 1; i <= 5; i++) {
(function (num) {
setTimeout(function () {
console.log(num);
}, num * 1000);
})(i);
}
在上述示例中,我们使用立即执行函数创建一个独立作用域,并将 i
的值传递给内部函数,从而确保每个计时器都能正确地输出各自的值。
总结: 在 TypeScript 中,闭包是非常有用的概念。通过闭包,我们可以创建私有变量、延长变量生命周期以及解决循环中的问题。需要注意的是,在使用闭包时要避免潜在的内存泄漏问题,确保及时释放不再需要的资源。
11. 结构体
在 TypeScript 中,结构体(Struct)是一种自定义的数据类型,用于组织相关字段的集合。结构体允许开发人员定义一个包含不同字段的复合数据类型。
在 TypeScript 中,结构体可以通过使用接口(interface)来模拟,并定义结构体的字段和其对应的类型。可以将结构体理解为一个没有方法的类,它仅仅用于描述数据的形状。
以下是一个简单的 TypeScript 结构体示例:
interface Person {
name: string;
age: number;
address: string;
}
let person: Person = {
name: "John Doe",
age: 25,
address: "123 Main St",
};
console.log(person);
在上述示例中,我们定义了一个名为 Person
的接口,该接口包含了 name
、age
和 address
这三个字段,并指定了它们的类型。然后,我们创建了一个 person
的变量,符合 Person
接口的定义,并给予其相应的值。
通过使用结构体,我们可以很方便地组织和操作相关字段,并且可以很容易地对结构体进行扩展或修改。
需要注意的是,TypeScript 的结构体只是一种类型定义的方式,它在运行时并不会真正存在。编译后的 JavaScript 代码中并没有结构体的概念,只有对应字段的属性。
12. 接口
在 TypeScript 中,接口(Interface)是一种用于定义对象的类型的抽象规范。它描述了对象应该具有的属性、方法和其他成员。
在接口中,我们可以定义属性的类型、方法的参数和返回类型,以及可选属性、只读属性和索引签名等。接口提供了一种约定,用于定义对象的结构和行为,并帮助开发人员在代码中进行类型检查和推断。
以下是一个简单的 TypeScript 接口示例:
interface Person {
name: string;
age: number;
sayHello: () => void;
}
let person: Person = {
name: "John Doe",
age: 25,
sayHello: () => {
console.log("Hello!");
},
};
console.log(person.name); // 输出: John Doe
person.sayHello(); // 输出: Hello!
在上述示例中,我们定义了一个名为 Person
的接口,该接口描述了一个人的属性和行为。Person
接口具有 name
(字符串类型)和 age
(数字类型)这两个必需的属性,以及一个无参且无返回值的 sayHello
方法。
然后,我们创建了一个 person
的变量,并将其指定为 Person
类型。该 person
变量必须符合 Person
接口的定义,也就是具有 name
、age
和 sayHello
这三个成员。
通过使用接口,我们可以明确地指定对象的结构和行为,以便在代码中进行类型检查和推断。当我们使用一个对象时,TypeScript 可以根据接口的定义检查我们是否遵循了该接口的规范。
除了定义对象接口外,接口还可以描述函数类型、类类型、可索引类型等。
需要注意的是,接口并不会在编译后的 JavaScript 代码中保留。它仅用于类型检查和类型推断,在编译时会被擦除。
在 TypeScript 中,接口(Interface)用于描述对象的结构和行为。接口提供了一种定义规范的方式,用于定义对象的属性、方法和类型。
下面是一个详细的讲解 TypeScript 接口的示例:
interface Person {
name: string;
age: number;
sayHello: () => void;
}
let person: Person = {
name: "John Doe",
age: 25,
sayHello: function() {
console.log(`Hello, my name is ${this.name}`);
},
};
person.sayHello(); // 输出: Hello, my name is John Doe
在上述示例中,我们定义了一个名为 Person
的接口,它描述了一个拥有 name
、age
和 sayHello
这三个属性的对象。其中,name
是一个字符串类型,age
是一个数字类型,sayHello
是一个无返回值的函数。
接着,我们创建了一个符合 Person
接口定义的 person
对象,并给予相应的属性和方法。
通过接口的使用,我们可以:
- 规定对象的属性和类型:接口定义了对象应该包含哪些属性和对应的类型。对象必须满足接口的要求,包括属性名和类型的匹配。
- 规定对象的行为:接口中可以定义对象的方法,规定了对象应该具有的行为。
- 保证类型安全性:TypeScript 在编译阶段会检查类型声明的一致性,如果对象不符合接口的定义,编译器会产生错误提示。
此外,接口还支持可选属性、只读属性、索引签名和继承等特性,使得它非常灵活和功能强大。
interface Circle {
readonly radius: number;
color?: string;
}
interface NamedShape extends Circle {
name: string;
}
let circle: NamedShape = {
name: "Circle",
radius: 5,
color: "red",
};
circle.radius = 10; // 错误:只读属性不可修改
在上述例子中,我们扩展了 Circle
接口,在 NamedShape
接口中继承了 Circle
,并添加了一个 name
属性。
通过上述详细讲解,你应该对 TypeScript 中的接口有了更好的理解。接口是一种强大的工具,可以帮助开发人员明确对象的结构和行为,为代码提供更好的可读性和可维护性。