對于JavaScript而言,只有(大)Object,沒有(小)object
object 只是 typeof 返回的一個字符串
typeof null === "object" // true
typeof {} === "object" // true
對于TypeScript來說,同時存在 object 和 Object
object
object 是TypeScript v2.2 引入的新類型,用于正式表示對象類型。
至此,TypeScript的原始類型(number、string、bigint、boolean、symbol、null、undefined、object)對應的正是JavaScript定義的 8 種內置類型:Number、String、BigInt、Boolean、Symbol、Null、Undefined、Object。
當然,TypeScript還定義了其他重要的類型:unknown、never、void、數(shù)組、元組、函數(shù)等
object 表示任何非原始值類型,包括對象、函數(shù)、數(shù)組等
當對object類型的變量賦予原始值時,TS編譯器會報錯
let a: object;
a = {};
a = [1, 2, 3];
a = [1, true, "abc"];
a = () => 1;
a = 11; // error 不能將類型"number"分配給類型"object"
JavaScript WeakMap 要求鍵必須是對象,TypeScript 在定義 WeakMap 時 使用的正是 object 約束鍵的類型
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
TS把 JavaScript Object 分成了兩個接口來定義:
-
Object接口(類型) 用于定義JS Object的原型對象Object.prototype
interface Object {
constructor: Function;
toString(): string;
toLocaleString(): string;
valueOf(): Object;
hasOwnProperty(v: PropertyKey): boolean;
isPrototypeOf(v: Object): boolean;
propertyIsEnumerable(v: PropertyKey): boolean;
}
-
ObjectConstructor用于定義Object自身的屬性,如Object.create()
interface ObjectConstructor {
new(value?: any): Object;
(): any;
(value: any): any;
readonly prototype: Object;
getPrototypeOf(o: any): any;
getOwnPropertyNames(o: any): string[];
create(o: object | null): any;
defineProperty<T>(o: T, p: PropertyKey, ...): T;
freeze<T>(a: T[]): readonly T[];
freeze<T extends Function>(f: T): T;
freeze<T>(o: T): Readonly<T>;
// ...
}
Object 的所有實例都繼承了 Object 接口的所有屬性/方法:
function f(x: Object): { toString(): string } {
return x; // OK
}
object 類型也可以訪問Object接口上定義的所有屬性/方法
let bar: object = {};
bar.toString(); // "[object Object]"
bar.hasOwnProperty("abc"); // false
有趣的是,由于JavaScript的裝箱拆箱機制,基本類型有能力訪問Object.prototype原型對象上的屬性。
因此,在 TS Object 類型可以同時接受引用類型和基本類型(不包括undefined和null)。但 object 類型不能接受原始值。
let b: Object = 3; // OK
let h: object = 4; // error
因此,在約束類型為非原始值類型時,應當始終使用 object!
需要注意的是,如果Object類型的值對象屬性名與Object接口定義的屬性沖突,則TS編譯報錯。
let b: Object = {
toString() { return 123 } // Error
};
而 object 類型不會。
{ }
{ } 描述一個沒有成員的對象,試圖訪問它的任何屬性時,TS都會編譯錯誤。
但仍然可以訪問 Object 類型上的所有屬性/方法
const obj: {} = {};
obj.toString(); // "[object Object]"
{} 也可以被賦予原始值
let foo: {};
foo = 3; // OK
雖然 Object 和 {} 都可以接受基本類型的值,但并不包括 null 和 undefined。
// 不能將類型 null 分配給類型 {}
let foo: {} = null; // error
// 不能將類型 undefined 分配給類型 Object
let bar: Object = undefined; // error
可以明顯感覺到,{ } 與 Object 的效果幾乎一樣,即 {} == Object,但 Object 更規(guī)范。
object 是一個寬泛的通用的非基本類型
let foo: { [key: string]: string } = {};
let bar: object = {};
bar = foo; // OK
// 不能將類型 object 分配給類型 { [key: string]: string; }
foo = bar; // Error
總結
object 是TypeScript v2.2引入的一種非基本類型,不能被賦予原始值。
Object 是對TypeScript對JavaScript Object.prototype原型對象的定義,是所屬對象類型的頂層類型,即所有對象類型都繼承了Object中定義的屬性/方法。同時,由于JavaScript的拆箱裝箱機制,Object類型的變量可以被賦予原始值,而基本類型也可以訪問Object中定義的屬性/方法。
{} 是一個沒有任何成員的對象類型,它可以訪問Object中定義的屬性/方法,也可以被賦予原始值。
因此,在約束對象類型時,我們應該始終使用object!
其實,不止有 Object 與 object,還有 Number 與 number、Boolean 與 boolean、String 與 string 等等。
Object、Number、Boolean 都定義在TypeScript內置的 .d.ts 中,對我們是可見的;而 object、number、boolean 這些TS的內置原始類型 都是不可見的。
在開發(fā)中,我們應當始終使用這些原始類型,而不是使用Object、Number、Boolean