Scala 代码片段到 TypeScript(如何转换抽象类型成员)

2024-02-06

我在 Scala 中有一小段值级别和类型级别列表

sealed trait RowSet {
  type Append[That <: RowSet] <: RowSet

  def with[That <: RowSet](that: That): Append[That]
}

object RowSet {

  case object Empty extends RowSet {
    type Append[That <: RowSet] = That

    override def with[That <: RowSet](that: That): Append[That] = that
  }

  case class Cons[A, B <: RowSet](head: A, tail: B) extends RowSet { self =>
    type Append[That <: RowSet] = Cons[A, tail.Append[That]]

    override def with[That <: RowSet](that: That): Append[That] = Cons(head, tail ++ that)
  }
}

现在,我正在尝试将其转换为 TypeScript。由于我们没有抽象类型成员 https://docs.scala-lang.org/tour/abstract-type-members.html功能,我似乎找不到不需要在某些时候进行类型转换的解决方案。

我目前在 TypeScript 中拥有的内容(也可以在操场 https://www.typescriptlang.org/play?#code/IYIwzgLgTsDGEAJYBthjAgSgewO4GUBTRAbwCgFKFRIZ4FcBLCACwB4AVF4RQgDwiEAdgBMMOAsQB8AClY8AXAi48AlEolEIZAL5kyEAJ4AHQggCCx06M4tGGfoNHi8WgDTLuvAcLFZX0ggAvBRUXPYIjr4YAMLYQmBsjEIAZoRQFh7JaRkAQlIIAPwIcQls5h6W1iJsuR4qEFIFSg0A3PooaBgAogC2xkaRPs7%20kqShlMYAriDIjLAMzOwNQ05%20mtJyXi1e6p48CORUxwhQxFNQQgjyEO3Henpknegl8YkVCLmr0aNaBVEjDbjY6wN7QKbwbBQGTTWbzU6EYAieLIQwIFiIkRKD6wuYLM5IlFoiDARjIJS5VSHCYnMBTUzQ1R3KiPY64%20FMVi2A4A9YBRpbRT7CB7UrvSpWXy1epeJrUk5UM4QC5XISEXCvBJbewAOgxSI8rF1JLJOs5LEFIuoGCqUrqwqkqhpDw6YIQfGCCDVGrFMgArB5vQg%20gNDE7QQlEGigl71ZqwDIAER2ROBuMhozht0AL09fDNSxkYaAA)

abstract class RowSet {
    abstract with<That extends RowSet>(that: That): RowSet
}

type Append<This extends RowSet, That extends RowSet> =
    This extends Cons<infer A, infer B> ? Cons<A, Append<B, That>> : That;

class Empty extends RowSet {
    public with<That extends RowSet>(that: That): That {
        return that;
    }
}

class Cons<A, B extends RowSet> extends RowSet {
    constructor(public readonly head: A, public readonly tail: B) {
        super();
    }

    public with<That extends RowSet>(that: That): Cons<A, Append<B, That>> {
        return new Cons(this.head, this.tail.with(that) as Append<B, That>)
    }
}

const x = new Cons(5, new Empty)    // Cons<number, Empty>
const y = new Cons("hi", new Empty) // Cons<string, Empty>
const z = x.with(y)                 // Cons<number, Cons<string, Empty>> 

我感兴趣的是我们是否可以避免在这里进行转换:

return new Cons(this.head, this.tail.with(that) as Append<B, That>)

看来 TypeScript 理解该值实际上是Append<B, That>因为它不允许投射到任何不同的东西,例如Append<B, B>或类似的东西。但因为我们使用with from abtract class RowSet我们最终得到Cons<A, RowSet>.

我们能否以不同的方式定义 RowSet,以便 TypeScript 在没有我们帮助的情况下正确推断所有内容?也许有不同的抽象类型成员转换方式(从 Scala 转换时)?


感谢 Oleg Pyzhcov 的评论,我能够在没有任何手动类型转换的情况下使其工作。 F-bounded 多态性被建议作为解决这个问题的一种方法,事实证明它确实有帮助

解决方案看起来像这样,不需要类型转换,一切都按预期工作

abstract class RowSet<T extends RowSet<T>> {
    abstract with<That extends RowSet<That>>(that: That): Append<T, That>
}

type Append<This extends RowSet<This>, That extends RowSet<That>> =
    This extends Cons<infer A, infer B> ? Cons<A, Append<B, That>> : That;

class Empty extends RowSet<Empty> {
    public with<That extends RowSet<That>>(that: That): That {
        return that;
    }
}

class Cons<A, B extends RowSet<B>> extends RowSet<Cons<A,B>> {
    constructor(public readonly head: A, public readonly tail: B) {
        super();
    }

    public with<That extends RowSet<That>>(that: That): Cons<A, Append<B, That>> {
        return new Cons(this.head, this.tail.with(that))
    }
}

const x = new Cons(5, new Empty)    // Cons<number, Empty>
const y = new Cons("hi", new Empty) // Cons<string, Empty>
const z = x.with(y)                 // Cons<number, Cons<string, Empty>> 

你可以检查一下

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 代码片段到 TypeScript(如何转换抽象类型成员) 的相关文章

随机推荐