Scala 片段到 TypeScript(如何转换抽象类型成员) [英] Scala snippet to TypeScript (how to convert abstract type members)

查看:46
本文介绍了Scala 片段到 TypeScript(如何转换抽象类型成员)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a small snippet of value level and type level list in 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.由于我们没有抽象类型成员功能,我似乎找不到在某些时候不需要类型转换的解决方案.

Now, I'm trying to convert this thing to TypeScript. As we don't have the Abstract Type Members feature, I cannot seem to find a solution which doesn't require to type cast at some point.

我现在有什么打字稿(也可在游乐场)

What I currently have in TypeScript (also available on Playground)

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>> 

我感兴趣的是我们是否可以避免在这里投射:

What I'm interested in is if we can avoid casting here:

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

TypeScript 似乎理解该值实际上是 Append 因为它不允许转换为任何不同的内容,例如Append 或类似的东西.但是因为我们使用了 abtract class RowSet 中的 with,所以我们最终得到了 Cons.

It seems that TypeScript understands that the value is actually Append<B, That> as it doesn't allow to cast to anything different, e.g. Append<B, B> or something similar. But because we use with from abtract class RowSet we end up with Cons<A, RowSet>.

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

Can we define RowSet differently, so that TypeScript correctly infers everything without our help? Maybe there is a different way of conversion of abstract type members (when converting from Scala)?

推荐答案

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

Thanks to Oleg Pyzhcov's comment I was able to make it work without any manual type casting. F-bounded polymorphism was suggested as a way to tackle this problem, and it turns out that it does help here

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

The solution looks like this, no type casting is needed, everything works as expected

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>> 

可以检查它游乐场

这篇关于Scala 片段到 TypeScript(如何转换抽象类型成员)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆