TypeScript 联合类型&类型断言
联合类型
联合类型就是类型的“或”操作。
我们来看这个例子:
let seven: number;
seven = 7;
seven = 'Seven'; // 会报错,报错信息:不能将类型“Seven”分配给类型“number”
上面代码会报错。当然我们将它改成 any 类型,但是更好的方式是使用联合类型
let seven: number | string;
seven = 7;
seven = 'Seven';
使用联合类型的话,只能访问两个类型共有的属性和方法,看下图。
习题:为变量 animal
声明合适的联合类型
let animal: _____;
animal = 'panda';
animal = 10;
animal.valueOf(0);
A. number | string
B. number | undefined
C. string | undefined
D. undefined | null
解析
我们需要对 animal
声明合适的变量,我们先来分析下面的运算:
animal = 'panda';
animal = 10;
这两步运算需要 animal
声明为 string
或者 number
。
animal.valueOf();
valueOf
方法是 string
,number
,boolean
共有的。故选 A。
类型断言
类型断言,就是断定它一定是这个类型。
我们来看下这个例子:
let seven: number | string;
seven.toFixed(3);
seven.length;
seven.toString();
目前运行上面代码,会报错,看看报错信息。那我们改写代码,让其不报错呢?
可以使用 as 进行类型断言。
let seven: number | string;
(seven as number).toFixed(3);
// 断言成 string 类型
(seven as string).length;
seven.toString();
习题:关于类型断言,下面描述错误的是?
A. 类型断言可以将一个联合类型的变量,指定为一个更加具体的类型
B. 不能将联合类型断言为不存在的类型
C. 类型断言是一种类型转换。
TypeScript 的类型系统是辅助工具,不会左右我们代码的逻辑,只会尽力的反馈类型给我们,所以类型系统不是一种类型转化。故选 C。
资料:类型断言的两种语法
在之前的学习中我们已经知道如何通过类型断言来预判值的类型,从而访问其属性,我们来看如下代码。
let seven: number | string;
(seven as number).toFixed(3); // 类型断言的第一种语法
<string>seven.length; // 类型断言的第二种语法
上述代码都能通过编译,因为他们都是符合规范的类型断言语法。
这里有一点需要注意,如果在 TypeScript 里面写 JSX 代码,是不能使用 <string>seven.length
来进行断言的,因为此时的 < >
会被识别为 JSX 语法。
资料:断言成 any 类型
看到标题可能很多同学会有疑问,为什么要断言为 any 类型?之前不是说要尽量让类型明确吗。
其实这里并不冲突,为了让代码清晰便于阅读,在使用TypeScript 开发的过程中我们一定要尽量避免声明 any 类型。但是在实际的开发过程中,难免遇到某些场景使得 TypeScript 无法编译通过,这里例举以下两个场景。
方法被调用的时候,实际传入的参数有可能是一个更加具体的值
我们来看如下代码:
function handler (e: Event) {
let touchEvent = e as TouchEvent;
}
上方代码可以通过编译,但是如下代码却会报错
function handler (e: Event) {
let $element = e as HTMLElement; // 类型“Event”不可转换为类型“HTMLElement”。类型“Event”中缺少属性“accessKey”。
}
这里我们期望的 $element 是一个 DOM 元素,所以 TS 会尝试去访问 e 是否存在 DOM 元素所必须有的属性,第一个访问的就是 accessKey 属性,因为这里的 e 是 Event 类型,发现访问不到,就会提示错误。
这时如果我们需要强行声明,我们可能就需要 将值断言为 any,类似如下代码:
function handler (e: Event) {
let $element = e as any as HTMLElement; // 双重断言
}
这里也可以理解为进行了双重断言,最终通过编译。
引入第三方库,造成无法通过编译
假设一个场景,我们引入了一个较老版本的 html2canvas 库,其在 windows 对象上绑定了 html2canvas 函数,我们的用法可能是如下代码:
import './html2canvas';
let $element = document.body;
window.html2canvas($element, canvas => {
console.log(canvas.toDataURL());
}); // 类型“Window”上不存在属性“html2canvas”
这时候我们可以将 window 断言为 any 类型来避免编译不通过
import './html2canvas';
let $element = document.body;
(window as any).html2canvas($element, canvas=>{
console.log(canvas.toDataURL());
});
转载自:https://juejin.cn/post/7027642653323821093