TypeScript 2.2 引入了一个新的 object 类型。它表示任何非基本类型。以下是 JS 的基本类型:

上述以外类型都被认为是基本类型,可以用新的 object 类型表示:

// 所有基本类型 type Primitive = | string | boolean | number | bigint | symbol | null | undefined; // 所有非基本类型 type NonPrimitive = object;

使用 object 类型的类型声明

随着 TypeScript 2.2 的发布,标准库的类型声明已经更新,以使用新的 object 类型。例如,object.create()object.setprototypeof() 方法现的参数类型是 object | null

interface ObjectConstructor { create(o: object | null): any; setPrototypeOf(o: any, proto: object | null): any; // ... }

将基本类型的值作为参数传递给 Object.setPrototypeOf()Object.create() 会导致在运行时抛出类型错误。TypeScript 现在捕获这些错误并在编译时提示错误:

const proto = {}; Object.create(proto); // OK Object.create(null); // OK Object.create(undefined); // Error Object.create(1337); // Error Object.create(true); // Error Object.create("oops"); // Error

object 类型的另一个用例是 ES6 引入的 WeakMap 数据结构。它的键必须是对象,不能是基本类型值:

interface WeakMap<K extends object, V> { delete(key: K): boolean; get(key: K): V | undefined; has(key: K): boolean; set(key: K, value: V): this; }

object vs Object vs {}

可能令人困惑的是,TypeScript定义了几个具有相似名称但表示不同概念的类型:

  • object
  • Object
  • {}

上面已经讲过 object 类型,现在来看看 Object{}

Object 类型

TypeScript 定义了另一个与新 object 类型几乎同名的类型,那就是 Object 类型。object (小写)表示所有非基本类型,而 Object (大写)描述所有 JS 对象共有的功能。例如,它包括 toString()hasOwnProperty() 方法。

在TypeScript附带的lib.es6.d.ts文件中,Object类型定义如下:

interface Object { // ... /** Returns a string representation of an object. */ toString(): string; /** Returns a date converted to a string using the current locale. */ toLocaleString(): string; /** Returns the primitive value of the specified object. */ valueOf(): Object; /** * Determines whether an object has a property with the specified name. * @param v A property name. */ hasOwnProperty(v: string): boolean; /** * Determines whether an object exists in another object's prototype chain. * @param v Another object whose prototype chain is to be checked. */ isPrototypeOf(v: Object): boolean; /** * Determines whether a specified property is enumerable. * @param v A property name. */ propertyIsEnumerable(v: string): boolean; }

空类型 {}

还有另一种类型与之非常相似:{},即空类型。它描述了一个本身没有成员的对象。当咱们试图访问此类对象上的任意属性时,TypeScript 会提示编译时错误

// Type {} const obj = {}; // Error: 类型“{}”上不存在属性“prop” obj.prop = "value";

但是,仍然可以使用在 Object 类型上定义的所有属性和方法,这些属性和方法通过JS 的原型链调用:

// Type {} const obj = {}; // "[object Object]" obj.toString();

字符串索引签名类型的点属性

在 TypeScript 2.2 之前,如果想访问带有字符串索引签名的类型的任意属性,就必须使用[]符号,但不允许使用.符号访问

interface Dictionary<T> { [key: string]: T; } const portNumbers: Dictionary<number> = {}; // OK portNumbers["http"] = 80; // Error: Property 'http' does not exist on type 'Dictionary<number>'. portNumbers.http = 80;

TypeScript 2.2 取消了这个限制。现在可以使用 []. 符号访问属性。在许多情况下,不再需要像这样令人不快的变通方法:

// 笨拙的方式 (portNumbers as any).http = 80;

请注意,类型必须定义显式字符串索引签名,以便用.符号访问对任意属性都是类型正确的。在类型使用上使用.符号访问未知属性仍然是一个错误,因此,对于以下代码,TypeScript 2.2 仍然会给出一个编译时错误:

const portNumbers = {}; // OK portNumbers["http"] = 80; // Error: Property 'http' does not exist on type '{}'. portNumbers.http = 80;

如果仔细想想,就会发现这很有意义:如果 TypeScript 没有为这段代码提供一个错误,那么就没有对拼写错误的属性名的保护。在 JS 中访问属性时,大多数时候将使用表示法,但也可以使用括号表示法作为转义。

有了这个较松的限制,对于常用JS 开发的人员来说更容易使用。如果咱们要将现有的 JS 代码基础迁移到 TypeScript,这尤其有用。给定适当的字符串索引签名,在这些情况下,就会获得更少的类型错误,并且不再需要使用类型注释注释点属性访问,这只是为了让编译器通过。

原文:

https://mariusschulz.com/blog/the-object-type-in-typescript