《Effective TypeScript》条款21 - 类型扩展
本文主要通过一些实际的代码示例,来帮助大家理解什么是类型扩展
,本文主要内容如下:
- 什么是类型扩展
- 代码示例
- 总结
什么是类型扩展?
TypeScript 需要从你指定的单一值中决定一组可能的值,这个过程成为类型扩展
代码示例
interface Vector { x: number; y: number; z: number; }
function getComponent(vector: Vector, axis: keyof Vector) { return vector[axis]; }
当你使用它时,TypeScript会提示一个错误.
//~类型string的参数不能赋值给类型 "x"|"y"|"z"的参数
报错的原因在于,x
被推断为string,而getComponent的第二个参数则是期望得到一个更加具体的单位类型
。
这就是类型扩展在起作用,所以导致这里产生了一个错误。
x被推断为string,因为typescript允许这样的代码:
let x = 'x';x = 'a'; x = 'b';
typescript试图在特殊性和灵活性之间找到平衡,一般的规则是,一个变量的类型不应该在它被声明后改变,所以string 比 string|Regexp或者string|string[]或者any更合理。
TypeScript给了一些方法控制类型扩展过程,其中一种就是const
,如果你用const而不是let,var来声明变量,就会得到一个更窄的类型。
const x = "x"; //x的类型为"x",而不是string
;
然而const对数组和对象来说仍然无效,因为在js中,对象自身不变的情况下,对象里面的属性是可以改变的。
比如:
const v = {x:1}
;
v的类型可以被推断到任意程度,最具体的为:{readonly x :1}
,一般化的是{x:number}
,再一般化的就是{[key:string]:number}
或者object
了。
对于对象来说,Typescript 的类型扩展算法会把对象中的每个元素当作是用let赋值了,所以,const v = {x:1}
的类型 就是 {x:number}
;
我们可以通过Typescript 提供的方法来覆盖Typescript 的默认行为。
- 提供一个明确的类型标注
const v:{x:1|3|5} = {x:1}
- 为类型检查器提供额外的上下文
通过传递值作为函数的参数
- 使用const断言
// const断言是纯粹的运行在类型空间的东西
const v1 = {x:1,y:1};//类型为{x:number,y:number}
const v2 = {x:1 as const,y:1};//类型为 {x:1,y:number}
const v3 = {x:1,y:2} as const; //类型为 {x:readonly x :number,readonly y:number}
当你在一个值后面写as const的时候,TypeScript会把它推断成最窄的类型.
更鲜明的例子:
const a1 = [1,2,3];//类型为 number[]
const a2 = [1,2,3] as const;//类型为readonly [1,2,3]
总结
- 了解TypeScript是如何通过扩展常量来推断类型的
- 熟悉影响这种行为的方法:const , 上下文,和 as const注释。