typescript中的unknown和any类型

96 阅读3分钟

参考文章:juejin.cn/post/684490…

any类型

在 TypeScript 中,任何类型都可以被归为 any 类型。这让 any 类型成为了类型系统的 顶级类型 (也被称作 全局超级类型)。

这是一些我们赋值给 any 类型的代码示例:

// demo1
let value: any;

value = true;             // OK
value = 42;               // OK
value = "Hello World";    // OK
value = [];               // OK
value = {};               // OK
value = Math.random;      // OK
value = null;             // OK
value = undefined;        // OK
value = new TypeError();  // OK
value = Symbol("type");   // OK
// demo2
let value: any;

value.foo.bar;  // OK
value.trim();   // OK
value();        // OK
new value();    // OK
value[0][1];    // OK

这许多场景下,这样的机制都太宽松了。使用any类型,可以很容易地编写类型正确但是执行异常的代码。如果我们使用 any 类型,就无法享受 TypeScript 大量的保护机制。

unknow类型

就像所有类型都可以被归为 any,所有类型也都可以被归为 unknown。这使得 unknown 成为 TypeScript 类型系统的另一种顶级类型(另一种是 any)。

let value: unknown;

value = true;             // OK
value = 42;               // OK
value = "Hello World";    // OK
value = [];               // OK
value = {};               // OK
value = Math.random;      // OK
value = null;             // OK
value = undefined;        // OK
value = new TypeError();  // OK
value = Symbol("type");   // OK

对 value 变量的所有赋值都被认为是类型正确的。

当我们尝试将类型为 unknown 的值赋值给其他类型的变量时会发生什么?

let value: unknown;

let value1: unknown = value;   // OK
let value2: any = value;       // OK
let value3: boolean = value;   // Error
let value4: number = value;    // Error
let value5: string = value;    // Error
let value6: object = value;    // Error
let value7: any[] = value;     // Error
let value8: Function = value;  // Error

unknown 类型只能被赋值给 any 类型和 unknown 类型本身。 假如对unknow类型执行某些操作,看看接下来会发生什么

let value: unknown;

value.foo.bar;  // Error
value.trim();   // Error
value();        // Error
new value();    // Error
value[0][1];    // Error

将 value 变量类型设置为 unknown 后,这些操作都不再被认为是类型正确的

小结:

  • 定义为unknown类型和any类型的变量可以进行重复赋值
  • 不允许对unknow类型的变量执行任意操作,而对any类型的变量进行任意操作不会有任何问题

操作unknown类型

我们可以通过不同的方式将 unknown 类型缩小为更具体的类型范围,包括 typeof 运算符,instanceof 运算符和自定义类型保护函数。

对unknown类型使用类型断言

前一节中,我们缩小了unknown类型的范围,并指定了其可能的具体类型,针对具体类型再执行安全的操作,这是比较推荐的做法。

如果要强制编译器信任类型为unknown的值为给定类型,则可以使用类型断言:

const value: unknown = "Hello World";
const someString: string = value as string;
const otherString = someString.toUpperCase();  // "HELLO WORLD"

如果我们确定unknow类型的具体类型,则使用断言不会有任何问题。假如错误地指定了类型,并执行了错误操作,可能会导致运行时错误。

联合类型中的unknown类型

type UnionType1 = unknown | null;       // unknown
type UnionType2 = unknown | undefined;  // unknown
type UnionType3 = unknown | string;     // unknown
type UnionType4 = unknown | number[];   // unknown
type UnionType5 = unknown | any; // any

any之外,unknow类型可以吸收任何类型。

交叉类型中的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

在交叉类型中,包含unknow类型不会改变结果。