首页 > 解决方案 > TypeScript 泛型与 Java 有何不同?

问题描述

以下代码会在 Java 中产生预期的类型错误,但 TypeScript 并不认为这是错误。这是设计使然,还是 TypeScript 中的错误?

abstract class UnitType<T extends UnitType<T>> {
    ...
}

class Unit<T extends UnitType<T>> {
    ...
}

class Length extends UnitType<Length> {
    static meters: Unit<Length> = new Unit<Length>()
}
class Angle extends UnitType<Angle> {
    static degrees: Unit<Angle> = new Unit<Angle>()
}


class UnitizedNumber<T extends UnitType<T>> {
    constructor(value: number, unit: Unit<T>) {
        ...
    }
}

// Length and Angle are not compatible, so this should be an error.
const foo: UnitizedNumber<Length> = new UnitizedNumber<Length>(1, Angle.degrees)

事实上,TypeScript 甚至不认为这是一个错误:

const meters: Length = new Angle()

TypeScript 是否将所有类视为结构类型而不是名义类型?我习惯于 Java 和 Flow 将类视为名义类型。

标签: typescriptgenericstype-parameterstructural-typingnominal-typing

解决方案


好吧,我的怀疑是正确的,TypeScript 目前将类视为结构类型,但计划对名义类型提供更多支持

根据https://michalzalecki.com/nominal-typing-in-typescript/强制 TypeScript 将类视为名义类型的一种方法是使用私有属性:

class Length extends UnitType<Length> {
    private __nominal: void
    static meters: Unit<Length> = new Unit<Length>()
}
class Angle extends UnitType<Angle> {
    private __nominal: void
    static degrees: Unit<Angle> = new Unit<Angle>()
}

但是,这仍然不会导致上述所需的错误。我必须确保 type 参数Unit实际上用于导致错误:

class Unit<T extends UnitType<T>> {
    type: T
    constructor(type: T) {
        this.type = type
    }
}

const foo: UnitizedNumber<Length> = new UnitizedNumber<Length>(1, Angle.degrees)

“Unit”类型的参数不能分配给“Unit”类型的参数。“角度”类型不能分配给“长度”类型。类型具有私有属性“名称”的单独声明。(2345)


推荐阅读