这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战
any 类型
我们来看一个例子:
let seven: number = 7;
seven = 'Seven';
运行上面代码,就会报错,因为 TS 不允许将类型“Seven”分配给类型“number” 的。
那现在怎么办呢?
我们可以把 number 改成 any 类型?
let seven: any = 7;
seven = 'Seven';
当然除了上面显式地指定 any 类型之外,我们还可以在定义变量的时候, 不给赋值,然后通过类型推论的方式,自动推论出 any 类型。
let seven;
seven = 7;
seven = 'Seven';
那么 any 类型有什么坏处呢?
如果是 number 类型的话,我们使用 seven. 的话,编辑器就会有对应的提示,比如有哪些方法,方法是做什么的。当我们使用方法的时候,编辑器也会提示出这个方法的参数是什么。
修改成 any 类型之后,就不会有提示。
let seven: number = 7;
seven.toFixed(3);
所以 any 类型不能滥用,那么我们什么时候使用 any 类型呢?
- 第三方库没有提供类型文件时
- 类型转换遇到困难时
- 数据结构(json)太复杂时
基本包装对象
概念
JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。
原始数据类型包括:布尔值、数值、字符串、null、undefined 以及 ES6 中的新类型 Symbol,在这里我们需要记住一点:所有的原始数据类型都没有属性(property)。
如上所述,在 JavaScript 中字符串被视为原始数据类型而不是对象类型,但是我们来看下面一段代码。
let text='hello';
console.log(text.toUpperCase()); // HELLO
这里很明显可以看出 text 有一个 toUpperCase 的属性(property)。那么是否上述结论不正确呢?如果 text 不是对象类型,为什么它具有 toUpperCase,toLowerCase 等属性呢?
先来一个简单的结论:JavaScript 会在原始数据类型和对象类型之间做一个迅速的强制性切换。
针对上述代码的详细解释就是:当我们试图访问 text 的 toUpperCase 属性时,JavaScript 会通过 new String(text) 来强制将字符串的值转换为一个对象类型,这个对象就是包装对象(wrapper object)。
它继承了 string 的所有方法,并且被用于获取其属性(property)上的引用(reference)。一旦属性被调用后,这个包装对象就会被废弃。
所以上述代码可以理解为实际是执行了如下操作:
let text = (new String('hello')).toUpperCase();
TypeScript 中类型声明时需要关注的包装对象问题
在之前的学习中,我们已经知道 TypeScript 拥有强大的类型系统,但是在赋值的时候,我们要注意如下问题。
let isDoing: boolean = true; // 编译通过
let isTesting: boolean = Boolean(1) // 编译通过
let isDone: boolean = new Boolean(1); // 编译失败
第三行代码会编译出错,这是为什么呢?有了上面提到的包装对象概念,相信大家也就能理解了,因为通过 new Boolean() 生成的值实际上是一个包装对象,并非原始数据类型。此处我们期望的 isDone 是一个原始数据类型,所以 TypeScript 会编译失败。
数值和字符串的赋值与上述代情况类似,就不再赘述。