Object
及其实例提供的内置接口在本章中,我们将研究与类及其实例相关的 TypeScript 类型。
考虑以下类
class Counter extends Object {createZero() {
static new Counter(0);
return
}: number;
valueconstructor(value: number) {
super();
.value = value;
this
}increment() {
.value++;
this
}
}// Static method
= Counter.createZero();
const myCounter .ok(myCounter instanceof Counter);
assert.equal(myCounter.value, 0);
assert
// Instance method
.increment();
myCounter.equal(myCounter.value, 1); assert
图 2 中的图表显示了类 Counter
的运行时结构。该图中有两条对象原型链
Counter
的对象组成。类 Counter
的原型对象是其超类 Object
。myCounter
的对象组成。该链从实例 myCounter
开始,然后是 Counter.prototype
(包含类 Counter
的原型方法)和 Object.prototype
(包含类 Object
的原型方法)。在本章中,我们将首先探讨实例对象,然后探讨作为对象的类。
接口指定对象提供的服务。例如
interface CountingService {: number;
valueincrement(): void;
}
TypeScript 的接口按 结构 工作:为了使对象实现接口,它只需要具有正确类型和正确名称的属性。我们可以在以下示例中看到这一点
: CountingService = new Counter(3); const myCounter2
结构化接口很方便,因为即使对于已经存在的对象,我们也可以为其创建接口(即,我们可以在事后引入它们)。
如果我们事先知道某个对象必须实现某个给定的接口,那么尽早检查它是否实现了该接口通常是有意义的,以避免以后出现意外。我们可以通过 implements
对类实例执行此操作
class Counter implements CountingService {// ···
; }
注释
.increment
)和自身属性(例如 .value
)。类本身也是对象(函数)。因此,我们可以使用接口来指定它们的属性。这里的主要用例是描述对象的工厂。下一节将给出一个示例。
以下两个接口可用于支持其实例与 JSON 相互转换的类
// Converting JSON to instances
interface JsonStatic {fromJson(json: any): JsonInstance;
}
// Converting instances to JSON
interface JsonInstance {toJson(): any;
}
我们在以下代码中使用这些接口
class Person implements JsonInstance {fromJson(json: any): Person {
static if (typeof json !== 'string') {
new TypeError(json);
throw
}new Person(json);
return
}: string;
nameconstructor(name: string) {
.name = name;
this
}toJson(): any {
.name;
return this
} }
这就是我们可以立即检查类 Person
(作为对象)是否实现了接口 JsonStatic
的方法
// Assign the class to a type-annotated variable
: JsonStatic = Person; const personImplementsJsonStatic
以下进行此检查的方法似乎是个好主意
: JsonStatic = class implements JsonInstance {
const Person// ···
; }
但是,这实际上行不通
Person
进行 new
调用,因为 JsonStatic
没有构造函数签名。Person
具有 .fromJson()
之外的静态属性,TypeScript 将不允许我们访问它们。Object
及其实例提供的内置接口查看 TypeScript 的内置类型是有益的
一方面,接口 ObjectConstructor
用于类 Object
本身
/**
* Provides functionality common to all JavaScript objects.
*/
declare var Object: ObjectConstructor;
interface ObjectConstructor {new(value?: any): Object;
: any;
(): any): any;
(value
/** A reference to the prototype for a class of objects. */
readonly prototype: Object;
/**
* Returns the prototype of an object.
* @param o The object that references the prototype.
*/
getPrototypeOf(o: any): any;
}
另一方面,接口 Object
用于 Object
的实例
interface Object {/** The initial value of Object.prototype.constructor is the standard built-in Object constructor. */
: Function;
constructor
/** Returns a string representation of an object. */
toString(): string;
}
名称 Object
在两个不同的 语言级别 使用了两次
考虑以下类
class Color {: string;
nameconstructor(name: string) {
.name = name;
this
} }
此类定义创建了两个东西。
首先,一个名为 Color
的构造函数(可以通过 new
调用)
.equal(
assert, 'function') typeof Color
其次,一个名为 Color
的接口,它与 Color
的实例相匹配
: Color = new Color('green'); const green
以下是 Color
确实是一个接口的证明
interface RgbColor extends Color {: [number, number, number];
rgbValue }
不过,有一个陷阱:使用 Color
作为静态类型并不是一个非常严格的检查
class Color {: string;
nameconstructor(name: string) {
.name = name;
this
}
}
class Person {: string;
nameconstructor(name: string) {
.name = name;
this
}
}
: Person = new Person('Jane');
const person: Color = person; // (A) const color
为什么 TypeScript 在 A 行没有报错?这是由于结构类型化:Person
和 Color
的实例具有相同的结构,因此在静态上是兼容的。
我们可以通过添加私有属性来使这两组对象不兼容
class Color {: string;
name= true;
private branded constructor(name: string) {
.name = name;
this
}
}
class Person {: string;
name= true;
private branded constructor(name: string) {
.name = name;
this
}
}
: Person = new Person('Jane');
const person
// @ts-expect-error: Type 'Person' is not assignable to type 'Color'.
// Types have separate declarations of a private property
// 'branded'. (2322)
: Color = person; const color
在这种情况下,私有属性会关闭结构类型化。