小记Typescript - 任意类型
为了方便学习和调试,我们安装以下几个库:
## 可以修改镜像源的库,可以不按照(因为NodeJS我已经设置为淘宝的镜像源了)
npm i xmzs -g
## 安装该库,为了直接调试TS文件,例如:ts-node index.ts
npm i ts-node -g
## 初始化当前项目(生产package.json配置文件)
npm init -y
## 创建声明文件,也就是支持ts-node
npm i @types/node -D
any 类型 和 unknown 顶级类型
any
(没有强制限定哪种类型,随时切换类型都可以 我们可以对 any 进行任何操作,不需要检查类型)
在编写代码时,有时并不清楚一个值是什么类型,这时就需要用到any类型,它是一个任意类型,定义为any类型的变量就会绕过TypeScript的静态类型检测。对于声明为any类型的值,可以对其进行任何操作,包括获取事实上并不存在的属性、方法,并且 TypeScript 无法检测其属性是否存在、类型是否正确。
我们可以将一个值定义为any类型,也可以在定义数组类型时使用any来指定数组中的元素类型为任意类型:
let value: any;
value = 123;
value = "abc";
value = false;
const array: any[] = [1, "a", true];
- 声明变量的时候没有指定任意类型默认为any
let anys;
anys = '123'
anys = true
- any 类型会在对象的调用链中进行传导,即any 类型对象的任意属性的类型都是 any,如下代码所示:
let obj: any = {};
let z = obj.x.y.z; // z的类型是any,不会报错
z(); // success
需要注意:不要滥用any类型,如果代码中充满了any,那TypeScript和JavaScript就毫无区别了,所以除非有充足的理由,否则应该尽量避免使用 any ,并且开启禁用隐式 any 的设置。
注意:弊端如果使用any 就失去了TS类型检测的作用
unknown
TypeScript 3.0中引入的 unknown 类型也被认为是 top type,主要用来描述类型并不确定的变量 ,但它更安全。与 any 一样,所有类型都可以分配给unknown。
unknown 类型比any更加严格当你要使用any的时候可以尝试使用unknown
- unknown 不能作为子类型只能作为父类型 any可以作为父类型和子类型
//unknown 可以定义任何类型的值
let value: unknown;
value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = null; // OK
value = undefined; // OK
value = Symbol("type"); // OK
//这样写会报错unknow类型不能作为子类型只能作为父类型 any可以作为父类型和子类型
//unknown类型不能赋值给其他类型
let names:unknown = '123'
let names2:string = names
//这样就没问题 any类型是可以的
let names:any = '123'
let names2:string = names
//unknown可赋值对象只有unknown 和 any
let bbb:unknown = '123'
let aaa:any= '456'
aaa = bbb
-
如果是any类型在对象没有这个属性的时候还在获取是不会报错的
如果是any类型在对象没有这个属性的时候还在获取是不会报错的
let obj:any = {b:1}
obj.a
如果是unknow 是不能调用属性和方法
let obj:unknown = {b:1,ccc:():number=>213}
obj.b
obj.ccc()
对于any,来看一个例子:
let value: any
console.log(value.name)
console.log(value.toFixed())
console.log(value.length)
上面这些语句都不会报错,因为value是any类型,所以后面三个操作都有合法的情况,当value是一个对象时,访问name属性是没问题的;当value是数值类型的时候,调用它的toFixed方法没问题;当value是字符串或数组时获取它的length属性是没问题的。
当指定值为unknown类型的时候,如果没有缩小类型范围的话,是不能对它进行任何操作的。总之,unknown类型的值不能随便操作。那什么是类型范围缩小呢?下面来看一个例子:
function getValue(value: unknown): string {
if (value instanceof Date) {
return value.toISOString();
}
return String(value);
}
这里由于把value的类型缩小为Date实例的范围内,所以进行了value.toISOString(),也就是使用ISO标准将 Date 对象转换为字符串
使用以下方式也可以缩小类型范围:
let result: unknown;
if (typeof result === 'number') {
result.toFixed();
}
关于 unknown 类型,在使用时需要注意以下几点:
-
任何类型的值都可以赋值给 unknown 类型:
let value1: unknown; value1 = "a"; value1 = 123; -
unknown 不可以赋值给其它类型,只能赋值给 unknown 和 any 类型:
let value2: unknown; let value3: string = value2; // error 不能将类型“unknown”分配给类型“string” value1 = value2; -
unknown 类型的值不能进行任何操作:
let value4: unknown; value4 += 1; // error 对象的类型为 "unknown" -
只能对 unknown 进行等或不等操作,不能进行其它操作:
value1 === value2; value1 !== value2; value1 += value2; // error -
unknown 类型的值不能访问其属性、作为函数调用和作为类创建实例
let value5: unknown; value5.age; // error value5(); // error new value5(); // error
在实际使用中,如果有类型无法确定的情况,要尽量避免使用 any,因为 any 会丢失类型信息,一旦一个类型被指定为 any,那么在它上面进行任何操作都是合法的,所以会有意想不到的情况发生。因此如果遇到无法确定类型的情况,要先考虑使用 unknown。