Typescript高级技巧-基本类型中的const

487 阅读2分钟

使用对象初始化变量时,TypeScript 认为该对象的属性是可以被更改的。例如,如果您编写了这样的代码:

const obj = { counter: 0 };
if (someCondition) {
  obj.counter = 1;
}

TypeScript 不会认为把 counter 从0改为1是错误的,只要 counter 符合数字类型就可以。

function handleRequest (url: string, method: 'GET' | 'POST') {}

const req = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method);
// 类型“string”的参数不能赋给类型“"GET" | "POST"”的参数。ts(2345)

在上面的示例中,req.method 被推断为字符串,而不是“GET”。TypeScript认为这段代码有错误。

有两种方法可以解决这个问题。

您可以通过在以下任一位置添加类型断言来更改推导的类型:

// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };
// Change 2
handleRequest(req.url, req.method as "GET");

更改1意味着“我希望 req.method 始终具有文本类型“GET”,从而防止在之后将“GUESS”分配给该字段。更改2意味着“我知道出于其他原因,req.method 具有值“GET”。

可以使用常量将整个对象转换为基本值作为其类型:

const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);

as const 后缀的作用类似于 const,但对于类型系统,确保所有属性都分配了文字类型,而不是更通用的基础类型,如字符串或数字。

这个最简单的声明,Typescript 会推断出 age 的类型是 number,你可以对它赋任何数值。

let age = 30
// age类型为number

但如果我们使用const声明这个变量,它的类型会变成什么?

const age = 30
// age类型为30

可以看到 30 就变成它的类型,而且再也无法更改。字符串也一样,会有这种限制。

如果对一个数组使用 const 定义,情况就有点不一样了,看下面的例子。它只是定义了 cars 为字符串数组类型,你还是可以对数组进行各种操作,比如插入一个数组元素之类的。

const cars = ['A', 'B', 'C']
// cars类型为string[]

如果你想限定死数组,那就需要加 as const, 如下:

const cars = [1, 2, 3, 4, 5]
// cars类型为readonly ["A", "B", "C"]

对象和数组差不多,如果直接 const 定义,你还是可以直接修改对象的字段,除非加入 as const,这样它会给每个字段加入 readonly, 并且使用基本值作为其类型。

例子:

获取对象属性值类型

type Person = { age: number; name: string; alive: boolean };
 
type I2 = Person[keyof Person];
//type I2 = string | number | boolean

把对象属性值推倒为联合类型

const RestfulMethod = {
  get: 'GET',
  post: 'POST',
  put: 'PUT',
  delete: 'DELETE'
} as const


type IRestfulMethod = typeof RestfulMethod
type TypeRestfulMethod = IRestfulMethod[keyof IRestfulMethod]
// type TypeRestfulMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'