Skip to main content

Other Types

any

any是一种使TypeScript代码退回到JavaScript代码编写的方案。它是TypeScript中一种特殊的类型,如果不希望特定的值导致类型检查错误,就可以使用any。当一个值是any类型,你可以访问它的任何属性,像一个函数调用它,给它赋值或者几乎任何其他语法合法的值。

由于any类型可以用于表示任意类型的值,因此主要用来描述不确定类型的变量。当你不想为了让TypeScript相信某行特定代码没问题而写出长的类型推断时,any类型很有用。

let obj: any = { x: 0 };
obj.bar = 100;
obj = 'hello';
const n: number = obj;
console.log(n);

any是其他类型的祖先,如果没有明确一个类型,并且TypeScript不能从上下文推断其类型,编译器将默认其类型是any。不过,通常情况下应避免这种情况,因为any类型不会被类型检查。可以使用noImplictAny编译选项标记任何隐式地any类型被视为一个错误,以减少程序出错的可能性。

由于使用any类型会破坏TypeScript对类型的检查,因此应尽量避免使用它。如果必须使用any类型,应尽量将它限制在一个小的范围内,并且尽量避免在其上执行不安全的操作,以避免类型错误和运行时错误。

let obj:any = {}
// runtime error: TypeError: obj.a is not a function
console.log(obj.a());
  1. any类型可以赋值给任何类型
let a : number;
let b: any = 'abc';
a = b
  1. 可以访问任何属性
let obj: any = {
a: 1
}
console.log(obj.b);
  1. 可进行属性的追加
let obj: any = {
a: 1
}
obj.b = 2
  1. 其它类型可赋值给any类型
let a;
let b = 1;
a = b

  1. 隐式any在严格模式下是不被允许的
function plus(a, b) {
return a + b
}

unknown

unknown是TypeScript 3.0版本新增的一个顶级类型。unknownany的类型安全对应类型。

其它类型可以分配给unknown,但是unknown不能分配给其它类型,除了本身和没有类型断言或基于类型窄化的控制流的any类型。

在使用时,如果不首先断言或窄化到更具体的类型,则不允许进行任何操作。

let myVar: unknown = 10;
let strVar: string = 'hello';

// 其它类型赋值给unknown类型
myVar = strVar;

// Type 'unknown' is not assignable to type 'string'.
strVar = myVar; // error

function test1(a: any) {
a.b();
}

function test2(a: unknown) {
// a' is of type 'unknown'.
a.b();
}

相比于any,编译器不会对unknown 类型跳过类型检查,因此更安全。使用之前,必须先检查其值的类型:

function test(a: unknown) {
if (typeof a === 'function') {
a();
} else if (typeof a === 'string') {
console.log(a.length);
} else {
// handle other cases
}
}

如果不知道一个值的类型,推荐使用unknown而不是any

any vs unknown

特征anyunknown
用法变量、参数、返回值变量、参数、返回值
类型检查不进行进行
可能的值任何类型未知类型,不能操作或使用未经验证的值
是否可赋值any与其它类型可相互赋值其它类型可以赋值给unknown,反之则不行
安全性低, 可能导致运行时错误高, 不能直接使用, 要进行类型检查
隐式转换支持不支持
显示转换可以显式断言缩小其类型必须显式类型断言确定其类型
可读性
维护性
缺点可能导致运行时错误, 不符合类型安全的最佳实践显式类型转换会增加代码复杂度, 并且必须小心处理未知的值和类型推断
使用时的建议避免, 尽量不使用推荐

never

never是TypeScript的底层类型,表示没有可分配的类型了,永远不会出现的类型。

never类型是每个类型的子类型,并且可以赋值给每个类型。相反,没有类型是never的子类型,并且其他任何类型不能赋值给never类型,除了never本身以外。

当TypeScript推断出一个变量的类型是never时,通常意味着该变量可用作断言,会防止编译任何它可能有值。

一般情况下,不应该手动将变量声明为never类型,而应该通过类型推断得出。

// 函数由于抛出错误, 无法正常结束返回
function error(message: string): never {
throw new Error(message);
}

error('Something went wrong');

// 死循环, 无法正常结束返回
function infiniteLoop(): never {
while (true) {
// something
}
}

never的使用场景:

  1. 当函数抛出一个异常或无法执行到最后一行代码时,返回值类型可声明为never。(如上案例)
  2. 当被任何永远不可能为真的类型保护窄化时,变量会获得never类型。
let strOrNum: string | number = 'hello';

if (typeof strOrNum === 'string') {
console.log(strOrNum.length);
} else if (typeof strOrNum === 'number') {
console.log(Number(strOrNum).toFixed(2));
} else {
// 类型被缩小为 never 类型,因为在之前的类型保护中已经排除了所有可能的类型
const unreachable: never = strOrNum;
}

object

要定义对象类型,只需列出其属性及其类型。

function printCoord(pt: { x: number; y: number }) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}

printCoord({ x: 3, y: 7 });

声明对象类型的方式:

// [key: type]:type
const obj1: { [key: string]: number } = { foo: 1, bar: 2 };
console.log(obj1);

const obj2: object = { foo: 1, bar: 2 };
console.log(obj2);

// 声明为interface
interface MyObj {
foo: number;
bar: number;
}

const obj3: MyObj = { foo: 1, bar: 2 };
console.log(obj3);

在TypeScript,object类型用来描述任何非基本类型的数据,不包括原始类型stringnumberbooleansymbolnull以及undefined ,包括函数、数组、Map等。一般来说,可以说object代表了所有的引用类型。

由于object类型表示具有任意属性的值,因此object类型可以作为所有对象的基础类型。如果any是所有类型的祖先,那么object可看做对象类型的祖先。

将一个变量声明为object类型时,仅仅表示一个具有任意属性的对象,且无法对这个对象的属性进行进一步的推断及访问,因此使用时可能会受到类型检查。如果需要更加准确的类型检查,可以使用具有特定属性及类型的类型别名type来表示对象类型。