TypeScript 的类型描述了一个变量可以保存哪种值。类型写在冒号后面,比如 let name: string,编译器会拒绝任何把错误种类的值放进去的代码。基础类型就是 JavaScript 的七种原始类型,再加上数组和对象这样的对象类型。
这些注解在编译时接受检查,然后被删除。实际运行的程序是普通的 JavaScript。
原始类型
| 类型 | 示例值 | 说明 |
|---|---|---|
string | "hi"、'hi'、`hi ${name}` | 文本。三种引号写法的类型相同。 |
number | 42、3.14、-0.5、NaN、Infinity | 所有数字,不论是不是整数。没有 int 或 float。 |
boolean | true、false | 只有这两个值。 |
bigint | 10n、BigInt(10) | 任意大小的整数。需要 ES2020 或更高的 target。 |
symbol | Symbol("id") | 一个唯一的值,主要用作对象的键。 |
null | null | “有意为空”。 |
undefined | undefined | “未设置”。读取不存在的属性时得到的也是它。 |
类型名都是小写的。对其中大多数类型,运行时的 typeof 会返回同样的单词,所以程序运行时,用 typeof x === "number" 就能检查一个值的原始类型。
类型注解
注解就是写在变量、参数或函数参数列表后面的 : Type。参数是最需要注解的地方,因为 TypeScript 猜不到调用者会传入什么。
如果变量在同一行初始化,注解通常是多余的:let count = 10 已经是 number 类型了。什么时候可以省略类型,请看类型推断页面。
类型错误就是编译错误
把错误类型的值赋给变量,编译器会在任何代码运行之前就停下来:
编译器输出:
index.ts(3,1): error TS2322: Type 'string' is not assignable to type 'number'.
解决办法是转换这个值:port = Number("3000");如果这个变量确实应该保存文本,就修改它的注解。
number:没有整数类型
JavaScript 把每个数字都存成 64 位浮点数,所以 TypeScript 只有一个 number 类型。整数在 Number.MAX_SAFE_INTEGER(2 ** 53 - 1)以内是精确的,超出这个范围就要用 bigint。
bigint 和 number 不能混用:exact + 1 是一个编译错误(TS2365:Operator '+' cannot be applied to types 'bigint' and '1'.,其中 '1' 是 1 的字面量类型),如果它真的运行了,在运行时也会抛出 TypeError。用 BigInt(1) 或 Number(exact) 显式转换其中一边,但要知道 Number 会对超出安全范围的值进行舍入。
如果你想要一个只接受整数的类型,TypeScript 无法对任意值表达这一点。在值进入程序的地方用 Number.isInteger 进行校验。
boolean
boolean 只有两个值:true 和 false。仅仅是真值的值(1、"yes")并不是布尔值,要用 Boolean(x) 或 x !== 0 把它们转换成布尔值。
null 和 undefined
开启 strict 时(从 TypeScript 6.0 起默认开启),null 和 undefined 是独立的类型,不属于 string、number 或任何其他类型。可能为空的变量要用联合类型写明:
在检查之前,读取可能为 undefined 的值的属性是一个编译错误。null 和 undefined 页面讲解了这些检查以及 ?. 和 ??。
数组和对象概览
不是原始类型的都是对象类型。你最先遇到的三种形式:
let tags: string[] = ["ts", "js"]; // array of strings
let point: { x: number; y: number } = { x: 1, y: 2 }; // object with two number properties
let greet: (name: string) => string = (n) => `hi ${n}`; // function type
每一种都有单独的页面:数组、元组(长度固定的数组)、对象类型和函数类型。
string、number、boolean 与 String、Number、Boolean
首字母大写的名称是 JavaScript 包装对象(new String("x"))的类型,而不是普通值的类型。注解请使用小写的名称。
index.ts(3,7): error TS2322: Type 'String' is not assignable to type 'string'.
'string' is a primitive, but 'String' is a wrapper object. Prefer using 'string' when possible.
把第一行的 String 改成 string,代码块就能运行。Number、Boolean、Symbol 和 BigInt 也是同样的道理。(Object 是另一回事:它几乎接受任何值,包括原始类型;参见对象类型。)
其他内置类型
还有几个类型很早就会遇到,每个都有单独的页面。
| 类型 | 含义 |
|---|---|
any | 对这个值关闭类型检查。尽量避免使用。 |
unknown | 任何值,但使用前必须先检查。 |
void | 函数不返回有用的值。 |
never | 根本没有值:总是抛出异常的函数,或者不可能出现的情况。 |
object | 任何非原始类型的值。 |
"red" | "green" | 字面量类型:只能是这几个确切的值。 |
常见问题
TypeScript 有整数类型吗?
没有。number 同时涵盖整数和小数,因为 JavaScript 把每个数字都存成 64 位浮点数。运行时用 Number.isInteger(n) 检查是否为整数;需要比 Number.MAX_SAFE_INTEGER(2 ** 53 - 1)更大的整数且不丢失精度时,使用 bigint(10n)。
TypeScript 中 string 和 String 有什么区别?
string 是原始类型,字符串字面量和模板字符串都是这个类型。String 是 new String("x") 创建的包装对象的类型。类型注解请始终使用小写的 string、number 和 boolean;把 String 赋给 string 是一个编译错误(TS2322)。
TypeScript 中有哪些原始类型?
和 JavaScript 一样,共有七种:string、number、boolean、bigint、symbol、null 和 undefined。其他一切(数组、对象、函数、类的实例)都是对象类型。
TypeScript 中如何声明带类型的变量?
在名称后面加冒号和类型:let count: number = 0;。对于函数,给每个参数加注解,返回类型可写可不写:function add(a: number, b: number): number。变量在声明时就初始化的话,通常可以省略注解,让 TypeScript 自动推断。
TypeScript 的类型在运行时存在吗?
不存在。编译器检查完类型后会把它们删除,所以实际运行的 JavaScript 没有任何注解。运行时要用 typeof、Array.isArray 和 instanceof 这样的 JavaScript 运算符来检查值。