11. 类型断言
TypeScript 提供了“类型断言”这样一种手段,允许开发者在代码中“断言”某个值的类型,告诉编译器此处的值是什么类型。TypeScript 一旦发现存在类型断言,就不再对该值进行类型推断,而是直接采用断言给出的类型。
对于没有类型声明的值,TypeScript 会进行类型推断,很多时候得到的结果,未必是开发者想要的。
type T = 'a'|'b'|'c';
let foo = 'a';
let bar:T = foo; // 报错
上面示例中,最后一行报错,原因是 TypeScript 推断变量foo的类型是string,而变量bar的类型是'a'|'b'|'c',前者是后者的父类型。父类型不能赋值给子类型,所以就报错了。
解决方法就是进行类型断言,在赋值时断言变量foo的类型
type T = 'a'|'b'|'c';
let foo = 'a';
let bar:T = foo as T; // 正确
上面示例中,最后一行的foo as T表示告诉编译器,变量foo的类型断言为T,所以这一行不再需要类型推断了,编译器直接把foo的类型当作T,就不会报错了。
总之,类型断言并不是真的改变一个值的类型,而是提示编译器,应该如何处理这个值。
类型断言不应滥用,因为它改变了 TypeScript 的类型检查,很可能埋下错误的隐患。
类型断言并不意味着,可以把某个值断言为任意类型。比如变量n是数值,无法把它断言成字符串,TypeScript 会报错。
类型断言要求实际的类型与断言的类型兼容,实际类型可以断言为一个更加宽泛的类型(父类型),也可以断言为一个更加精确的类型(子类型),但不能断言为一个完全无关的类型。
如果没有声明变量类型,let 命令声明的变量,会被类型推断为 TypeScript 内置的基本类型之一;const 命令声明的变量,则被推断为值类型常量。
// 类型推断为基本类型 string
let s1 = 'JavaScript';
// 类型推断为字符串 “JavaScript”
const s2 = 'JavaScript
TypeScript 提供了一种特殊的类型断言as const,用于告诉编译器,推断类型时,可以将这个值推断为常量,即把 let 变量断言为 const 变量,从而把内置的基本类型变更为值类型。as const断言只能用于字面量,不能用于变量。
对对象、数组使用as const,相当于使用了readonly
在一些地方我们使用一个变量时,TS可能会提示该变量可能为null或者undefined,需要我们使用判断来解决。但是现在TS提供了一个非空断言,如果你确定这个变量不会为空,那么在这个变量后面加上“!”,就能让TS不再对这个值进行检查。
另外,非空断言只有在打开编译选项strictNullChecks时才有意义。如果不打开这个选项,编译器就不会检查某个变量是否可能为undefined或null。
断言函数是一种特殊函数,用于保证函数参数符合某种类型。如果函数参数达不到要求,就会抛出错误,中断程序执行;如果达到要求,就不进行任何操作,让代码按照正常流程运行。
function isString(value:unknown):void {
if (typeof value !== 'string')
throw new Error('Not a string');
}
function toUpper(x: string|number) {
isString(x);
return x.toUpperCase();
}
上面示例中,函数isString()就是一个断言函数,用来保证参数value是一个字符串,否则就会抛出错误,中断程序的执行
以上是传统的断言函数,isString()的写法有一个缺点,它的参数类型是unknown,返回值类型是void(即没有返回值)。单单从这样的类型声明,很难看出isString()是一个断言函数。
为了更清晰地表达断言函数,TypeScript 3.7 引入了新的类型写法。
function isString(value:unknown):asserts value is string {
if (typeof value !== 'string')
throw new Error('Not a string');
}
上面示例中,函数isString()的返回值类型写成asserts value is string,其中asserts和is都是关键词,value是函数的参数名,string是函数参数的预期类型。它的意思是,该函数用来断言参数value的类型是string,如果达不到要求,程序就会在这里中断。
使用了断言函数的新写法以后,TypeScript 就会自动识别,只要执行了该函数,对应的变量都为断言的类型。
另外,断言函数的asserts语句等同于void类型,所以如果返回除了undefined和null以外的值,都会报错。
注意,断言函数与类型保护函数(type guard)是两种不同的函数。它们的区别是,断言函数不返回值,而类型保护函数总是返回一个布尔值。
function isString(
value:unknown
):value is string {
return typeof value === 'string';
}
上面示例就是一个类型保护函数isString(),作用是检查参数value是否为字符串。如果是的,返回true,否则返回false。该函数的返回值类型是value is string,其中的is是一个类型运算符,如果左侧的值符合右侧的类型,则返回true,否则返回false。
如果要断言某个参数保证为真(即不等于false、undefined和null),TypeScript 提供了断言函数的一种简写形式。
function assert(x:unknown):asserts x {
// ... 逻辑需要开发者自己实现
}
评论