【问题标题】:How to represent multiple types (union types) when targeting JavaScript以 JavaScript 为目标时如何表示多种类型(联合类型)
【发布时间】:2017-11-07 19:07:42
【问题描述】:

我想做的是使用可以是其他三种类型之一的泛型类型。

下面是一个函数示例:

fun <T> get(key: String) : T where T: String, T: Number, T: Boolean {}

上面的代码不起作用,我该怎么做呢?

【问题讨论】:

  • @JaysonMinard 是的,没错。我正在将一些具有联合类型的 Typescript 定义文件翻译到 Kotlin,这就是我想这样做的原因。尽管以下答案很好,但它们不符合我的需要。所以我现在只需要使用Any 类型。
  • 我对您的用例提出了明确的问题,并添加了一个针对 TypeScript / JS 目标的答案。

标签: kotlin kotlin-js-interop


【解决方案1】:

这不起作用,因为T 不能表示为位于String、Number 和Boolean 交集处的某种类型。

如果您想将类型限制为预定义类型列表,密封类是一个很好的解决方案。

sealed class MyData {
  class Bool(val data: Boolean) : MyData()
  class String(val data: String) : MyData()
  class Number(val data: Number) : MyData()
}

fun get(key: String): MyData = TODO()

【讨论】:

    【解决方案2】:

    对于 KotlinJS,您可以使用 ts2kt 将您的 TypeScript 定义转换为 Kotlin。它确实支持联合类型,但可能并非所有情况都是完美的。 tests for unionTypes in ts2kt 阐明了它们现在的处理方式,您可以针对 JavaScript 平台手动创建的任何内容执行类似的操作。

    issue #41 - to add better Union Type support 的 cmets 中提到了进一步的工作。最后,至少有一个discussion thread 的主题表明:

    在大多数情况下,在 JS 和 TS 中,联合类型用作重载的替代方法,因此在不久的将来,我们将尽可能使用重载。 此外,我们考虑提供额外的方法来为原生声明指定联合类型。

    还有另一个 Stack Overflow 问题正在讨论这个问题,并提供了一些当前选项:Kotlin and discriminated unions (sum types),它的答案在所有 Kotlin 目标平台上都有效。

    对于 JavaScript 目标,您可以考虑使用 dynamic type。我至少看到one test case in ts2kt 正在使用这种类型。此示例以以下 TypeScript 代码开头:

    declare class Foo
    
    type Key = Key2 | number;
    type Key2 = string | Foo;
    declare var fooKey: Key;
    
    declare function barKey(a: Key|number);
    declare function barList(a: List<Key>);
    declare function barArray(a: Key[]);
    
    interface Parent {
        (...children: Key[]): Foo;
    }
    

    并使用dynamic 作为返回类型代替联合类型生成此 Kotlin;在其他情况下,重载方法签名以处理联合类型(我添加的一些 cmets):

    external open class Foo
    
    // using dynamic in place of union type
    external var fooKey: dynamic /* String | Foo | Number */ = definedExternally
    
    // using method overloading in place of union type
    external fun barKey(a: String): Unit = definedExternally
    external fun barKey(a: Foo): Unit = definedExternally
    external fun barKey(a: Number): Unit = definedExternally
    
    // using dynamic in place of union type
    external fun barList(a: List<dynamic /* String | Foo | Number */>): Unit = definedExternally
    external fun barArray(a: Array<dynamic /* String | Foo | Number */>): Unit = definedExternally
    
    external interface Parent {
        // using method overloading in place of union type
        @nativeInvoke
        fun invoke(vararg children: String): Foo
        @nativeInvoke
        fun invoke(vararg children: Foo): Foo
        @nativeInvoke
        fun invoke(vararg children: Number): Foo
    }
    

    但同样,您应该查看所有ts2kt test cases for union types 以了解其他想法包括处理undefined。

    【讨论】:

      【解决方案3】:

      编译器如何知道在这种情况下返回的是什么类型? T 可能是任何东西,所以他们无法定义类似的东西。

      您可以定义三种特定于类型的方法:

      fun getString(key: String): String = ...
      fun getBoolean(key: String): Boolean= ...
      fun getInt(key: String): Int = ...
      

      (或 kevinmost 建议的包装方法)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-17
        • 2021-08-14
        相关资源
        最近更新 更多