前言
在 JavaScript 中,变量是没有类型的,变量的值的类型是在运行时确定的,这被称为动态类型。
这意味着可以在不同的时间将不同类型的值赋给同一个变量,并且 JavaScript 会在运行时根据当前赋给变量的值来确定其类型。
示例:
let a; // 声明一个变量 a
a = 10; // 此时 a 的类型被确定为数字类型
a = "hello JavaScript"; // 现在 a 的类型变为字符串类型
a
的类型随着每次赋值而改变。
JavaScript 会在运行时根据实际赋给变量的值来自动调整和处理其类型。这种动态类型的特性使得 JavaScript 非常灵活,但也可能导致一些难以察觉的错误,因为类型的变化可能会在不经意间发生。
例如,想要一个变量是数字并进行数学运算,但它在运行时被意外地赋值为字符串,就会出错。
let a = 10;
let b = 5;
console.log(a + b); // 15
// 假如经历了一系列逻辑操作,需要重新对 b 赋值 并计算结果
b = "5";
console.log(a + b); // "105",假如在别的地方要使用这个结果,会导致难以排查的错误。
JavaScript是动态类型语言,对类型的检查和约束相对较弱。
TypeScript 是 JavaScript 的超集,它支持与JavaScript几乎相同的数据类型,在 JavaScript 的基础上增加了静态类型系统。这意味着在 TypeScript 中,开发者需要在编写代码时,可以选择添加类型注释来明确指定变量、函数参数、函数返回值等的类型。
注意:TypeScript 的类型注释将始终位于被输入的内容之后。
基础类型
string
:字符串类型。
// 声明一个变量 str,同时指定 str 的类型为 string
let str: string;
// str 的类型设置为 string,从此以后,str 的值只能是 字符串类型
str = "Hello"; // 字符串类型
str = 123; // 编译错误: Type 'number' is not assignable to type 'string'.
在编写代码时,编辑器报错:不能将类型“number”分配给类型“string”。
因为变量str
的类型是string
。
可以使用模版字符串:
let name: string = `张三`;
let desc: string = `我的名字是 ${
name}`;
number
:数字类型。
数字类型不分int
和 float
,全是number
。
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;
除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量。
boolean
:布尔类型。
布尔类型只有两个值true
/ false
。
let isDone: boolean = false;
始终使用string
、number
或boolean
来表示类型。
数组类型
TypeScript有两种方式可以定义数组。
- 在基础数据类型后面接上
[]
,表示由此类型元素组成的一个数组:
let list1: number[] = [1, 2, 3]; // 数字数组,数组的每个元素都是number类型
let list2: string[] = ["list1", "list2"]; // 字符串数组,数组的每个元素都是string类型
let list3: boolean[] = [true, false, true]; // 布尔数组,数组的每个元素都是boolean类型
let arr: string[][] = [["a", "b"], ["c", "d"]]; // 声明一个二维字符串数组。
- 使用数组泛型,
Array<元素类型>
:
let list1: Array<number> = [1, 2, 3];
let list2: Array<string> = ["list1", "list2"];
let list3: Array<boolean> = [true, false, true];
元组 Tuple
TypeScript 中的元组(Tuple)是一种特殊的数组类型。
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
特点:
- 固定的元素数量和类型顺序
- 元组中的元素数量是明确的,并且每个位置的元素类型是固定的。
- 混合类型
- 可以在一个元组中包含不同类型的元素。
示例:
// 定义一个包含字符串、数字和布尔值的元组
let myTuple: [string, number] = ["Hello", 42];
// 访问元组中的元素,通过索引
console.log(myTuple[0]); // "Hello"
console.log(myTuple[1]); // 42
// 错误:Type 'string' is not assignable to type 'number'.(不能将类型“string”分配给类型“number”。)
myTuple[1] = "not a number"; // 编译错误:Type 'string' is not assignable to type 'number'.
// 错误:Type 'true' is not assignable to type 'undefined'.(不能将类型“true”分配给类型“undefined”。)
// 错误:Tuple type '[string, number]' of length '2' has no element at index '2'.(长度为 "2" 的元组类型 "[string, number]" 在索引 "2" 处没有元素。)
myTuple[2] = true;
// 错误:Argument of type 'boolean' is not assignable to parameter of type 'string | number'.(类型“boolean”的参数不能赋给类型“string | number”的参数。)
myTuple.push(true);
// 语句没有报错,why?
// myTuple.push("world");
TypeScript 的元组和数组的区别:
- 元组:具有固定数量的元素,且每个元素的类型是明确且固定的。元组对每个位置的元素类型有严格的约束。
- 数组:元素数量可以动态变化。如果指定了类型,如
number[]
,则要求所有元素都是指定的类型;如果未指定类型,元素类型可以不同(any
类型)。
枚举
枚举(Enum
)类型是对Java Script标准数据类型的一个补充。
枚举(Enum
)是一种为一组数值赋予有意义名称的方式。
默认情况下,从 0
开始为元素编号。
enum Color {
Red, Green, Blue}
console.log(Color);
// 输出以下结果
// {
// "0": "Red",
// "1": "Green",
// "2": "Blue",
// "Red": 0,
// "Green": 1,
// "Blue": 2
// }
代码定义了一个名为 Color
的枚举类型,其中 Red
被初始化为 0
,Green
为 1
,Blue
为 2
。
也可以手动为枚举成员赋值:
enum Color1 {
Red = 11,
Green = 22,
Blue = 33
}
console.log(Color1);
// 输出
// {
// "11": "Red",
// "22": "Green",
// "33": "Blue",
// "Red": 11,
// "Green": 22,
// "Blue": 33
// }
枚举成员可以通过两种方式访问:
let c: Color = Color.Red; // 通过枚举名.成员名
console.log(c); // 输出 0(默认情况)
let colorName = Color[2]; // 通过枚举值获取枚举名
console.log(colorName); // 输出 "Green"(默认情况)
Any
当一个变量被声明为 any
类型时,它可以被赋予任何类型的值,并且在对其进行操作时,TypeScript 编译器不会进行类型检查。
any
完全放弃了类型检查。
// 显式声明变量为any类型
let variable: any = 5;
variable = "Hello";
variable = true;
let list: any[] = [1, true, "free"]; // list 包含了不同的类型的数据
list[1] = 66;
// 隐式声明变量为any类型
// 声明变量 并且 不指定类型, TS 解析器会自动判断变量的类型为any
let variable1;
variable1 = "Hello";
variable1 = true;
在上述代码中,variable
、variable1
可以被随意赋值为不同类型的值。
any
类型的变量还可以赋值给任意类型的变量:
let variable: any = 5;
variable = "Hello";
variable = true;
let str : string;
str = variable;
console.log(str); // true; TS类型检查器不会再检查 变量 str 。
通常,只有在确实无法确定变量类型或者需要与旧的 JavaScript 代码进行交互且类型难以明确时,才建议使用 any
类型。
unknown
unknown
类型表示一个值的类型是未知的。
只有 any
类型和 unknown
类型的值可以赋给 unknown
类型的变量。
unknown
类型是一种比 any
更安全的类型,对 unknown
类型的值进行操作是受到限制的。
例如,如果有一个变量 x
的类型是 unknown
,在对其进行操作之前,必须先进行类型断言或类型缩小的检查:
let x: unknown;
// 错误,不能直接对 unknown 类型的值进行操作
// x.toUpperCase(); // 报错:x 的类型是 “未知”
if (typeof x === "string") {
// 经过类型缩小检查后,可以进行操作
x.toUpperCase();
}
可以对 x
进行任意赋值:
<