一. any类型
TypeScript允许我们对 any 类型的值执行任何操作,而无需事先执行任何形式的检查。即逃离类型检查。
1.变量声明为any类型,则可以将任何类型的值付给变量,可以在赋值过程中改变类型
let color: any = 'red';
color = 0xF00 //OK
2.变量被声明为any类型,可以在变量上访问任何属性,调用任何方法,即使不存在,.ts编译成.js会通过
let anything: any = '新华路前端肖队';
anything.name = 'zhangyx20'; //OK
console.log(typeof anything); //string
console.log(anything.name); //undefined
console.log(anything.age); //undefined
console.log(anything.sayHello()); //js报错,anything.sayHello is not a function
这样写greeter.ts编译成greeter.js不会报错,运行greeter.js,前三个不会报错,输出都是undefined,第四个会报错。
3.变量声明既没定义类型,也没赋值,则默认为any类型
let uncertain;
uncertain = '123'; //OK
uncertain = Number(uncertain); //OK
注意:如果变量声明时赋了值,如let uncertain = 1;相当于let uncertain: number = 1;之后再更改类型编译会报错
二. unknown类型
unknown和any和相似,TS中的所有类型均可以被归为any,也可以被归为unknown,即any和unknown都是TS的top type,区别在于any即时top type又是bottom type,而unknown只是top type。使用any类型,很容易会编写出编译正常但执行异常的代码,any不能默认保持安全。unknown解决了这一问题。
(一)
声明变量为unknown,则可以将任何类型的值付给变量,可以在赋值过程中改变类型。这一点和any是一样的
unknown类型只能被赋值给any和unknown类型。
先来看看any这么做会怎么样
let var1: any = 1;
let var2: string = var1; //OK,ts编译js通过,js运行也不报错
console.log(typeof var1) //number
console.log(typeof var2); //number
再来试试unknown
cinst uncertain: unknown;
const var1: unknown = uncertain; //OK
const var2: any = uncertain; //OK
const var3: number = uncertain; //编译报错:error TS2322: Type 'unknown' is not assignable to type 'number'.
const var4: object = uncertain; //编译报错:error TS2322: Type 'unknown' is not assignable to type 'object'.
在声明为unknown的变量上访问属性和方法
let uncertain: unknown = 1;
uncertain.name = 'zhangyx20'; //error TS2339: Property 'name' does not exist on type 'unknown'.
console.log(uncertain.name); //error TS2339: Property 'name' does not exist on type 'unknown'.
对声明为unknown的值执行赋值外的其他操作
let var1: unknown = 1;
var1 = var1 + 1; //greeter.ts:76:8 - error TS2365: Operator '+' cannot be applied to types 'unknown' and '1'.
const var1: unknown = 'hello world';
console.log(typeof var1) //string
const var2: string = var1.slice(6) //greeter.ts:77:27 - error TS2339: Property 'slice' does not exist on type 'unknown'.
实际上,对声明为unknown的值能够使用的运算符只有 ===,==,!==,!=这四个。
经过以上四点的试探,我们可以擅作主张TypeScript 不允许我们对类型为 unknown 的值执行任意操作。这是个具有很强预防性的机制。我们在使用unknown类型的值之前,首先要执行类型检查,缩小值的类型范围
(二)使用类型收缩
1. 使用instanceof运算符获得更具体的类型。
const var1: unknown = 'hello world';
let var2: string;
if(typeof var1 === 'string'){
var2 = var1.slice(6) //OK,编译通过
}
console.log(var2) //world
2.使用instanceof运算符获得更具体的类型。
const var1: unknown = new String('hello world');
let var2: string;
if(var1 instanceof String){
var2 = var1.slice(6) //OK,编译通过
}
console.log(var2); //world
3.使用自定义保护函数,缩小 unknown 类型范围。
下面这个例子声明了一个unknown类型的变量unknownValue,赋值为一个数组,现考虑将其所有元素转换为平方。可以自己写一个自定义保护函数,告诉TypeScript,我们知道自己在操作一个类型为unknown的变量。
const unknownValue: unknown = [1, 2, 3, 4, 5, 6];
//函数目的在于,告诉TypeScript,我们知道自己在操作一个类型为unknown,值为number-Array的变量
function isNumberArray(value: unknown): value is number[] {
return (
Array.isArray(value) &&
value.every(element => typeof element === "number")
);
}
if(isNumberArray(unknownValue)) {
unknownValue.map((value, index, self) => self[index] = value ** 2);
console.log(...unknownValue); //[2, 4, 9, 16, 25, 36]
}
(三)使用类型断言
通过类型断言,可以强制编译器信任类型为 unknown 的值为给定类型
const var1: unknown = 'Hello World';
console.log((var1 as string).toUpperCase()) //HELLO WORLD
const var2: unknown = 1;
//编译通过,转换为JS:var var2 = 1;console.log(var2.name);输出为undefined
console.log((var2 as { name: string }).name);
(四)联合类型
在联合类型中,unknown 类型会吸收任何类型,但是遇到any,会被吸收为any
type UnionType1 = string | unknown; // unknown
type UnionType2 = unknown | any; //any
let var1: string = 1; //报错,因为var1是string类型
let var2: UnionType1 = 2; //编译通过,因为var2是unknown类型
(五)交叉类型
在交叉类型中,任何类型都可以吸收 unknown 类型
type IntersectionType1 = unknown & null; // null
type IntersectionType2 = unknown & undefined; // undefined
type IntersectionType3 = unknown & string; // string
type IntersectionType4 = unknown & number[]; // number[]
type IntersectionType5 = unknown & any; // any
三. 什么时候用any,什么时候用unknown?
any和unknown相比,unknown更安全,迫使我们对变量执行额外的类型检查,而使用any基本上是放弃了TS的所有类型检查。在大部分使用any和unknown的场景都是为了使用top type这一点。个人认为any不能滥用,如果一个变量的类型是固定的,但是现在还不确定或者不想确定,就将其声明为unknown类型,通过断言或类型收缩来正确使用它。