跳到主要内容

基础语法/关键词

基础类型

在 TS 中,基本类型(注意:这里指的是声明变量时使用的 Type)包括 Boolean、Number、String、Array、Tuple、Enum、Unknown、Any、Void、Null、Undefined、Never、Object。其中 Number、String、Boolean、Symbol、Object 等在作为 Type 时,应使用小写形式。

  • boolean(布尔类型)
  • number(数字类型)
  • string(字符串类型)
  • array(数组类型)
  • tuple(元组类型) 常用于 hooks 返回结果
  • enum(枚举类型)
  • any(任意类型)
  • null 和 undefined 类型
  • void 类型
  • never 类型
  • unknown 可以表示任何类型,但是收窄版的 any,不能读取 unknown 上的方法 已经上 unknown 类型的值无法赋值给其他值
  • object 对象类型

在 JavaScript 中 null 表示 "什么都没有",是一个只有一个值的特殊类型,表示一个空对象引用,而 undefined 表示一个没有设置值的变量

默认情况下 null 和 undefined 是所有类型的子类型, 就是说你可以把 null 和 undefined 赋值给 number 类型的变量

而 never 是其他类型 (包括 null 和 undefined)的子类型,可以赋值给任何类型,代表从不会出现的值 但是没有类型是 never 的子类型,这意味着声明 never 的变量只能被 never 类型所赋值。 never 类型一般用来指定那些总是会抛出异常、无限循环

不过,很多时候我们不需要显式地声明变量的类型,可以让 TS 自动进行 type infer。如:

let foo = ''; // 变量 foo 的类型会被推导为 string

我推荐使用这种方式来进行代码的编写,不过在 TS 无法推导出类型的情况下,应当显式地声明类型。

Array 类型

在进行 Array 的类型声明时,推荐用简化方式进行声明:

const list: number[] = [1, 2, 3]; // 不简化的方法是Array<number>
// 如果Array的element是复杂对象时,建议先声明interface:
interface Record {
id: string;
description: string;
}

const records: Record[] = [];

注意:如果数组变量在声明的时候进行了初始化赋值,但赋值为空数组时,类型会被推导为 any[]。但是数组如果是 object 中的一个字段,被初始化为空数组时,类型会被推导为 never[]。示例如下:

const list = []; // any[]
const obj = {
list: [], // never[]
};

Tuple(固定数量!)

Tuple 可以用来声明固定 elements 数量(如 hooks 返回结果)的数组,并且每一项 element 的类型可知,每项的类型可以不相同。如下:

const x : [string, number] = ["hello", 10];
x[0] // string
x[1] // number
x[2] // TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'.
``

## const+enum 在编译时会将 enum 删除,会有更好的性能

```js
export const enum Snack {
Apple = 0,
Banana = 1,
Orange = 2,
Other = 3
}

直接编译成 var a = 0 而不是 var a = A.a

特殊符号

  • ! 非空断言操作符
  • ?· 可选链
  • ?? 空值合并运算符
  • ?: 可选属性
  • & 多种类型进行叠加
  • | 多种类型中的一种
  • _ 数字分割符号 eg: 1_23
  • <> 泛型
  • @ 装饰器语法
  • # 类的私有字段
  • -? 移除可选属性中的'?'

字面量类型

在一定程度可以减少函数重载

可以用字面量来作为类型对变量进行声明,这种情况用于我们已经清楚该变量能够取得值是可穷举的情况。 比如上一节中,对于 emit 函数的声明,因为我们可以确定它的 eventName 参数只可能是 event1 或 event2,所以可以这样对它进行声明:

function emit(eventName: "event1" | "event2", ...params: any[]): void {
// function implements.
}

使用字面量类型进行声明比起直接用 string 来声明的好处是,我们可以避免调用方在调用的时候传入'event3'这种我们不支持的参数。 另外,除了字符串字面量之外,还可以使用数字字面量来做同样的事情

function rollDice(): 1 | 2 | 3 | 4 | 5 | 6 {
return (Math.floor(Math.random() * 6) + 1) as 1 | 2 | 3 | 4 | 5 | 6;
}
const result = rollDice();

这是官方 Handbook 中的一个小例子,它限制了 rollDice 的返回值只能是 1 到 6 这几个数字。

类型的交并集

一个变量有能力拥有多种类型

这种时候我们就可以用到类型的并集来对变量进行声明。

let magicVal: string | number | boolean = 0;
magicVal = "hello world";
magicVal = false;

在另外一种情况下,

某个变量在满足了我们已经定义好的类型的情况下,还需要额外地满足另一些类型

Unions & Intersection Types

则使用类型的交集来进行声明。这里引用官方 Handbook 的一个例子来进行说明。

以下例子中 ArtworksResponse 和 ArtistsResponse 类型的变量,既要满足它们公共接口 ErrorHandling 的实现,又要分别满足自身对应的 Data 的实现。

interface ErrorHandling {
success: boolean;
error?: { message: string };
}
interface ArtworksData {
artworks: { title: string }[];
}
interface ArtistsData {
artists: { name: string }[];
}
// These interfaces are composed to have// consistent error handling, and their own data.type ArtworksResponse = ArtworksData & ErrorHandling;
type ArtistsResponse = ArtistsData & ErrorHandling;
const handleArtistsResponse = (response: ArtistsResponse) => {
if (response.error) {
console.error(response.error.message);
return;
}
console.log(response.artists);
};