首页 > 解决方案 > Typescript 可以强制执行类类型吗?

问题描述

在下面的示例中,我希望通过将变量声明c1为类型Coordinate,它要么被初始化为实例,Coordinate要么我会得到一个编译错误。

打字稿:

class Coordinate {
    x: number;
    y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    toString(): string {
        return `(${this.x},${this.y})`;
    }
};

const c1 : Coordinate = {x:1, y:2};             // <=== problem
const c2 : Coordinate = new Coordinate(3, 4);

console.log('c1', c1 instanceof Coordinate ? 'Coordinate' : 'not Coordinate');
console.log('c2', c2 instanceof Coordinate ? 'Coordinate' : 'not Coordinate');

console.log(`c1: ${c1}`);
console.log(`c2: ${c2}`);

汇编

官方节点typescript包编译这个打字稿代码没有错误或警告:

npx tsc --version
Version 4.0.3
npx tsc

实际输出:

c1 not Coordinate
c2 Coordinate
c1: [object Object]
c2: (3,4)

预期输出:

任何一个:

  1. const c1 : Coordinate = {x:1, y:2};导致编译错误,或

  2. c1 被强制转换为 的实例Coordinate

     c1 Coordinate
     c2 Coordinate
     c1: (1,2)
     c2: (3,4)
    

有没有一种编码或配置打字稿的方法来表现这些方式中的任何一种?我更喜欢编译器错误。我想要类似 cpp 的类型强制,而不是鸭子类型。

标签: typescript

解决方案


正如评论中已经提到的,Typescript 是结构化类型的,所以一般来说,您希望使用任何具有 ax或 a 的东西y都是有效的想法Coordinate。但是,我们可以解决这个问题。从同一个链接

当检查类的实例的兼容性时,如果目标类型包含私有成员,则源类型也必须包含源自同一类的私有成员。

所以如果我们给类一个私有成员(即使我们从不使用它),就像这样

class Coordinate {
    private _ignore: any;
    x: number;
    y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    toString(): string {
        return `(${this.x},${this.y})`;
    }
};

那么我们永远不能在Coordinate直接使用之外构建它

const c1 : Coordinate = {x:1, y:2}; // Error
const d1 : Coordinate = {_ignore: 0, x:1, y:2}; // Also an error

甚至d1失败,因为尽管它具有所有正确的字段名称,但私有名称并非来自正确的类。这使我们能够在需要时获得 Java 或 Scala 等语言的标称行为。

笔记:

如果您担心将字段添加到结构中,您也可以使用私有成员函数执行相同的技巧。

class Coordinate {
    x: number;
    y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }

    private _ignore(): void {}

    toString(): string {
        return `(${this.x},${this.y})`;
    }
};

这将具有相同的效果。


推荐阅读