TypeScript

TypeScript

  • 开始
  • 官方文档
  • 语言规范

›手册

文档说明

  • 文档约定
  • 历史版本

入门指南

  • 五分钟速览

手册

  • 数据类型
  • 变量声明
  • 接口
  • 类
  • 函数
  • 泛型
  • 枚举
  • 类型推断
  • 类型兼容
  • 高级类型

数据类型

简介

在编程时我们需要一些最简单的数据结构,比如:数字、字符串、结构体、布尔值等等,TypeScript 支持很多和 JavaScript 相同的数据类型,另外还有枚举类型。

布尔类型

最基本的数据类型是 true / false,在 JavaScript 和 TypeScript 中称为 boolean 值。

let isDone: boolean = false;  

数字类型

像 JavaScript 一样,TypeScript 中的所有数字都是浮点数值,这些浮点数值的类型称为 number。除了十六进制和十进制数字,TypeScript 还支持 ES2015 规范引入的二进制和八进制数字。

let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;

字符串

文本数据是在 JavaScript 中创建 Web 页面和服务端程序的另一基础部分。像其他语言一样,我们使用 string 类型来定义这些文本数据。和 JavaScript 一样,TypeScript 需要在数据起始和结束处加上单引号 ' 或双引号 "以表示该数据是字符串类型。

let color: string = "blue";
color = 'red';

还可以使用模板字符串,这种方式可以让定义的字符串跨行,同时内部可以嵌入表达式。模板字符串类型的数据起始和结束处需加上反引号 `,内嵌的表达式格式为 ${ expr }。

let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ fullName }.

I'll be ${ age + 1 } years old next month.`;

上面这段代码和下面的定义方式是一样的。

let sentence: string = "Hello, my name is " + fullName + ".\n\n" +
    "I'll be " + (age + 1) + " years old next month.";

数组

TypeScript 和 JavaScript 一样可以定义数组类型的数据。数组有两种定义方式,第一种方式使用数组内部元素的类型后加上 [] 的方式来定义数组:

let list: number[] = [1, 2, 3];

第二种方式使用泛型数组类型 Array<elemType> 定义:

let list: Array<number> = [1, 2, 3];

元组

元组实际是一个定长且每个位置元素类型确定的数组。但是这种数组内部元素的类型可以不一样。例如,你可能想表示一对由 string 和 number 构成的数据结构。

// 定义一个元组类型
let x: [string, number];
// 初始化
x = ["hello", 10]; // OK
// 错误的初始化方式
x = [10, "hello"]; // Error

通过已知索引值(~数字类型的值)去检索元组将返回对应的数据类型。

console.log(x[0].substring(1)); // OK
console.log(x[1].substring(1)); // Error, 'number' does not have 'substring'

当索引值越界的时候将返回错误。

x[3] = "world"; // Error, Property '3' does not exist on type '[string, number]'.

console.log(x[5].toString()); // Error, Property '5' does not exist on type '[string, number]'.

枚举

枚举是对 JavaScript 数据类型的一个很有效的补充。枚举使用 enum 定义。就像在 C# 语言中一样,使用枚举定义一组数字集合可以使代码可读性更好。

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

~枚举也可使用中文进行定义,Color.绿色 也是可以的。

枚举默认对内部成员从 0 开始编号(~枚举实际上就是数字,编号就是枚举每个成员的值)。你可以手动修改内部成员的编号。例如,我们可以让上面的枚举 Color 从 1 开始编号。

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

或者我们也可以手动指定所有枚举的编号。

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

枚举的一个很方便的功能是可以直接从数字值转换为枚举对应的名称(~返回的名称是个 string 类型的值)。例如,如果我们知道 2 这个数字值,但是我们不清楚该映射到上面的 Color 枚举的哪个成员,我们可以像下面这下查找对应的成员。

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];

console.log(colorName); // 返回 Color 枚举的 Green 成员。

~枚举成员的编号如果手动指定,则紧接着的下一个成员的编号将以前一个编号为基础按步长 1 递增。那这里就涉及一个问题了,请看下面这个例子。

enum Color {
  Red = 1,
  绿色 = 10,
  蓝色,
  白色 = 11
}

console.log(Color.蓝色); // line A
console.log(Color[11]); // line B

$这个例子里面 A 行输出 “11” , B 行输出 “白色” 。两个不同的枚举成员却拥有相同的值,可能会引起很多业务上的严重漏洞。请注意避免在代码中出现上面这个例子中的问题。

任意值

有些时候我们需要定义我们并不清楚具体类型的数据。这些数据有可能是动态生成的,例如来自用户或第三方库的数据。在这种情况下,我们需要放弃类型检查来让这些数据通过编译期类型检查。我们使用 any 标识这些未知类型的数据。

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

any 类型可以和已有 JavaScript 代码协同工作,它可以让代码在编译过程中逐渐加入或退出类型检查。在其他语言中,你可能觉得是 Object 类型在扮演这个角色,但是 Object 类型的变量仅允许你对其任意赋值,你不能在该变量上调用方法甚至是该变量里本来就存在的方法。

let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists 方法在运行时可能存在
notSure.toFixed(); // okay, toFixed 存在 (但编译器不会检查)

let prettySure: Object = 4;
prettySure.toFixed(); // Error: 属性 'toFixed' 在 Object 类型上不存在

~ any 指的是通过编译期检查,并不是说适用于运行期,如果在运行时 notSure 对象并没有 ifItExists 函数,那么 notSure.ifItExists(); 仍然会在运行时出错。上面代码中,notSure 在运行时的值为 4,而 number 类型的变量在原型链上是有 toFixed() 这个方法的。

注意: 避免使用 Object 类型。请尽量使用非基本类型 object 。详细原因请参阅[Do’s and Don’ts](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#general-types)部分。

any 类型也非常适合那种只知道部分数据类型的情况,比如包含多种数据类型元素的数组。

let list: any[] = [1, true, "free"];

list[1] = 100;

Void

void 的含义和 any 有些相反。void 表示没有任何的数据类型,通常 void 用作一个不返回任何值的函数的返回类型:

function warnUser(): void {
    console.log("This is my warning message");
}

定义 void 类型的变量没有任何用,因为你仅仅只能为其赋值为 null (仅当未指定--strictNullChecks时,请参阅下一部分)或 undefined。

let unusable: void = undefined;
unusable = null; // OK 如果未指定 `--strictNullChecks` 参数

Null 和 Undefined

在 TypeScript 中,null 和 undefined 都有各自的类型,分别为 null 和 undefined。像 void 一样,它们单独使用时并无太大用处。

// 不能为以下变量指定任何其他值
let u: undefined = undefined;
let n: null = null;

默认情况下,null 和 undefined 是其他所有类型的子类型。也就是说你可以指定 null 和 undefined 值给一个 number 类型的变量。

然而使用 --strictNullChecks 参数时,null 和 undefined 只能赋值给 any 类型和它们各自类型的变量(一个例外是 undefined 可以赋值给 void 类型的变量)。这能够避免许多常见的错误。$如果想要赋值 string 或 null 或 undefined 给变量,你可以使用联合类型 string | null | undefined 来定义这个变量。

let a: string | null | undefined;
a = "a string";
a = null;
a = undefined;

联合类型我们将在后面的章节中提到。

注意:我们鼓励在可能的情况下使用 --strictNullChecks 参数。但是在本手册中我们将假定它已关闭。

Never

never 类型表示永远不会出现值的类型。例如,never 通常作为始终抛出异常或无法结束(~无限循环)的函数或箭头函数的返回类型。当变量存在于类型保护中无法通过的检查项中,该变量成为 never 类型。类型保护我们将在后面的章节中提到。

never 类型是所有类型的子类型,也可以赋值给任何类型。然而 never 没有子类型,任何类型的值都不能赋值给 never (除了 never 自身),甚至 any 类型的值也不能赋值给 never 。

如下是一些返回 never 的函数:

// 返回 `never` 的函数不能有正常执行完成标志位。
function error(message: string): never {
    throw new Error(message);
}

// 推断返回值也是 `never`,虽然没有明确指定。
function fail() {
    return error("Something failed");
}

// 返回 `never` 的函数不能有正常执行完成标志位。
function infiniteLoop(): never {
    while (true) {
    }
}

更多例子:

// 不可能通过的类型保护检查项
function typeGuardThatNeverPass(value: any) {
  if (typeof value === "number" && typeof value === "string") {
    // 不可能有任何变量同时是number和string类型,此时value成为never类型
    value;
  }
}

// never类型错误用法
// 该函数在对变量a赋值后结束运行,是可以结束的函数,所以无法使用never作为返回类型
function cannotUseNeverType(): never {
    let a = 0;
}

// never没有子类型
let a: number = functionReturnsNeverType(); // 正确;该函数返回never类型
let b: never = 1; // 错误;不能将其他类型的值赋值给never类型变量
function functionReturnsNeverType(): never {
    throw new Error();
}

Object

object 类型用来表示非基本类型,即任何不是 number、string、boolean、bigint、symbol、null、undefined的类型。

使用 object 类型可以更好地表示 Object.create 之类的 API。例如:

declare function create(o: object | null): void;

create({ prop: 0 }); // OK
create(null); // OK

create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error

类型断言

~对应Java中的 类型强转。

有时候你可能会遇到比 TypeScript 更了解值的类型的情况。这种情况通常发生在我们清楚地知道某个实体变量的类型比当前定义的类型更为明确的时候。

类型断言告诉编译器:“相信我,我清楚我在做什么!”。类型断言和其他语言中的类型强转类似,但是类型断言不对数据本身做特殊检查或改造数据结构。类型断言无运行时影响,仅仅是在编译期被编译器使用。TypeScript 假定你已经执行了任何必要的特殊检查。

类型断言有两种形式,一种是单书名号的语法:

let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;

另外一种是 as 语法:

let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;

两种方式是一样的,可根据个人喜好选择一种使用。但是,当在 JSX 中使用 TypeScript 的时候,只能使用 as 语法(~因为 JSX 会把单书名号方式当做一个组件进行编译)。

关于 let

到现在你可能已经注意到了,我们一直在使用 let 替代你可能更熟悉的 JavaScript 中的 var。 let 是在 ES2015 规范中引入的,并且现在已经被视作标准用法了,因为它比 var 更安全。我们将在后续讨论相关细节。使用 let 可以避免很多 JavaScript 中的常见问题,所以你应该尽可能地使用它来代替 var。

← 五分钟速览变量声明 →
  • 简介
  • 布尔类型
  • 数字类型
  • 字符串
  • 数组
  • 元组
  • 枚举
  • 任意值
  • Void
  • Null 和 Undefined
  • Never
  • Object
  • 类型断言
  • 关于 let
Copyright © 2025 unimits