逐一攻破TypeScript: Const 断言

249 阅读2分钟

逐一攻破TypeScript: Const 断言

前言

懂得as const的意义,懂得 Const 断言的使用,就能轻松实现用数组/对象的键/值创建联合类型, 即以下实现:

const arr = ['a', 'b', 'c'] // => type arrValue = 'a' | 'b' | 'c'
const obj = { 'a': 1, 'b': 2, } // => type objKey = 'a' | 'b'; type objValue = 1 | 2

预备知识

  • typeof获取变量类型
  • keyof索引类型查询
const obj = { a: 1, b: 2 }
type objType = typeof obj // { a: number, b: number }
type keys = keyof objType // 'a' | 'b'

基础知识

官方解释 TypeScript 3.4 引入了一种新的字面量结构,称为*const*断言。它的语法是一个类型断言,const代替了类型名称(例如'hello' as const)。当我们用断言构造新的文字表达式时const,我们可以向语言发出信号

  • 不应扩大该表达式中的文字类型(例如,不要从"hello"string
  • 对象字面量获取readonly属性
  • 数组文字变成readonly元组

简而言之,使用const断言的变量,内部属性都是只读的,所以对象或数组的值都会被定义为字面量。

基础考察

1. 用数组的值创建联合类型

使用const断言与否,效果差异如下:

const arr = ['a', 'b', 'c'] // string[]
const arr1 = ['a', 'b', 'c'] as const   // readonly ['a','b','c']

type arrValue = typeof arr[number] // string
type arrValue1 = typeof arr1[number] // 'a' | 'b' | 'c'

2. 用对象的键名创建联合类型

3. 用对象的键值创建联合类型

const obj = {
    'a': 1,
    'b': 2,
} as const
// 等价于
// const obj: {
//     readonly a: 1;
//     readonly b: 2;
// }
type objKey = keyof typeof obj // 'a' | 'b'
type objValue = typeof obj[keyof typeof obj]    // 1 | 2

进阶考察

1. 用对象数组的键名创建联合类型

2. 用对象数组的键值创建联合类型

3. 用对象数组的指定键值创建联合类型

const objArr = [{
    'a': 1,
    'b': 2
}, {
    'a': 3,
    'b': 4,
}] as const
// 等价于
// const objArr: readonly [{
//     readonly a: 1;
//     readonly b: 2;
// }, {
//     readonly a: 3;
//     readonly b: 4;
// }]

type arrValues = typeof objArr[number] // {readonly a: 1,readonly b: 2} | {readonly a: 3,readonly b: 4}
type keys = keyof typeof objArr[number] // a | b
type values = typeof objArr[number][keys] // 1 | 3 | 2 | 4
type keyValues = typeof objArr[number]['a'] // 1 | 3

自我考察

  • 已知METHODS_MAP,如何实现正确实现request('/api',METHODS_MAP.GET)
const METHODS_MAP = { GET: 'GET',POST: 'POST'}
// => 实现
const request = (url: string, method: 'GET' | 'POST') => ({ url, method })
request('/api',METHODS_MAP.GET) // warn:类型“string”的参数不能赋给类型“"GET" | "POST"”的参数。
  • 实现
const METHODS_MAP = { GET: 'GET', POST: 'POST' } as const
// => 
const request = (url: string, method: keyof typeof METHODS_MAP) => ({ url, method })
request('/api', METHODS_MAP.GET)

为什么需要对常量METHODS_MAP进行Const断言呢?因为TypeScript 并没有针对类型做进一步的推断,从而因此保证了类型的灵活性。

const METHODS_MAP = { GET: 'GET', POST: 'POST'} // { GET: string, POST: string}

const METHODS_MAP = { GET: 'GET', POST: 'POST' } as const // { GET: 'GET' as const , POST: 'POST' as const }

总结

  • const断言允许我们编写更少的类型声明。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情