TypeScript 2.2 引入了一个新的 object
类型。它表示任何非基本类型。以下是 JS 的基本类型:
- string
- boolean
- number
- bigint
- symbol
- null
- undefined
上述以外类型都被认为是非基本类型,可以用新的 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,这尤其有用。给定适当的字符串索引签名,在这些情况下,就会获得更少的类型错误,并且不再需要使用类型注释注释点属性访问,这只是为了让编译器通过。
往期阅读
- 【TypeScript 进化史 — 破晓】一步一个脚印带你入门 TS
- 【TypeScript 进化史 — 1】non-nullable 的类型
- 【TypeScript 进化史 — 2】基于控制流的类型分析 和 只读属性
- 【TypeScript 进化史 — 3】标记联合类型 与 never 类型
- 【TypeScript 进化史 — 4】更多的字面量类型 与 内置类型声明
- 【TypeScript 进化史 — 5】将 async、await 编译到 ES3、ES5 (外部帮助库)
- 【TypeScript 进化史 — 6】对象扩展运算符和 rest 运算符及 keyof 和查找类型
- 【TypeScript 进化史 — 7】映射类型和更好的字面量类型推断
- 【TypeScript 进化史 — 8】字面量类型扩展 和 无类型导入
- 【TypeScript 进化史 — 9】object 类型 和 字符串索引签名类型的点属性
- 【TypeScript 进化史 — 10】更好的空值检查 和 混合类
- 【TypeScript 进化史 — 11】泛型参数默认类型 和 新的 –strict 编译选项
作者:Marius Schulz
链接:https://mariusschulz.com/blog/the-object-type-in-typescript
看完两件小事
如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:
- 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
- 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程
本文著作权归作者所有,如若转载,请注明出处
转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com