当Typescript类应该不同时,它们是等效的

  • 本文关键字:Typescript typescript
  • 更新时间 :
  • 英文 :


我正试图在Float32Array之上放置一个轻量级层来创建vec2和vec3。这里有一个例子:

class vec3 extends Float32Array {
//    w : number;
constructor() {
super(3);
//        this.w = 1;
}
static add3(x: vec3) : vec3 {
x[2] += 1;
return x;
}
};
class vec2 extends Float32Array {
constructor() {
super(2);
}
static add2(x: vec2) : vec2 {
x[1] += 1;
return x;
}
};
var test1: vec3 = new vec3();
vec3.add3(test1);
console.log(test1);
var test2: vec2 = new vec2();
vec3.add3(test2);                       // This should be an error
console.log(test2);

(TS游乐场连接(

Typescript认为这两个类是等价的,并允许vec3.add3(test2);

如果我取消注释定义w成员变量的行,它可以正确地理解它们是不同的类。

有没有办法区分这两类?

Typescript默认情况下使用结构类型,因此,如果您的类A被声明为具有公共字段xy以及名为foo的方法,则任何具有字段xy以及名为foo(具有匹配类型(的方法的对象都被视为A的实例。

然而,这一制度中有一个故意的漏洞。如果您的类有一个名为x私有字段,则只有该类的实际实例才被视为该类型的有效实例。具有名为x的字段的其他对象不兼容。

class vec3 extends Float32Array {
private __tag: unknown = {};
...
}
class vec2 extends Float32Array {
private __tag: unknown = {};
...
}

尽管这两个类具有相同的形状,并且都有一个名为__tag的字段,但由于字段是私有的,因此两者被认为是不兼容的。

看起来您可以通过在代码中故意放置一个错误来实现这一点,该错误会更改类的签名,但实际上不会占用结构中的任何空间:

class vec3 extends Float32Array {
// @ts-ignore: unused member to keep the type unique
__vec3_type : number;
constructor() {
super(3);
}
static add3(x: vec3) : vec3 {
x[2] += 1;
return x;
}
};
class vec2 extends Float32Array {
// @ts-ignore: unused member to keep the type unique
__vec2_type : number;
constructor() {
super(2);
}
static add2(x: vec2) : vec2 {
x[1] += 1;
return x;
}
};
var test1: vec3 = new vec3();
vec2.add2(test1);
console.log(test1);
var test2: vec2 = new vec2();
vec3.add3(test2);                       // This should be an error
console.log(test2);

这是我想要的,不需要为对象本身添加任何空间。

我想这是因为Typescripts决定使用结构类型而不是名义类型:https://www.typescriptlang.org/docs/handbook/type-compatibility.html

如果没有任何品牌和双下划线,您可以创建一个通用类,将维度的数量保存为类的属性:

class Float32ArrayN<T extends number> extends Float32Array {
constructor(public dimensions: T) {
super(dimensions);
}
}
const a = new Float32ArrayN(4)
a.dimensions // type: 4
const b: Float32ArrayN<3> = new Float32ArrayN(4) // error

现在,由于dimensions是不同的文字数字类型,每个类在结构上是不同的。现在你可以让你的子类像这样:

class vec3 extends Float32ArrayN<3> {
constructor() {
super(3);
}
static add3(x: vec3) : vec3 {
x[2] += 1;
return x;
}
};
class vec2 extends Float32ArrayN<2> {
constructor() {
super(2);
}
static add2(x: vec2) : vec2 {
x[1] += 1;
return x;
}
};

正如你所料,它会抛出错误:

var test1: vec3 = new vec3();
vec3.add3(test1);
console.log(test1);
var test2: vec2 = new vec2();
vec3.add3(test2);             // error
console.log(test2);
var test3: vec3 = new vec2()  // error

游乐场

最新更新