如何在定位JavaScript时表示多种类型(联合类型)

时间:2017-06-06 16:44:05

标签: kotlin kotlin-js-interop

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

这是一个有功能的例子:

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

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

3 个答案:

答案 0 :(得分:8)

这不起作用,因为T无法表示为位于StringNumberBoolean交叉点的某种类型。

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

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

答案 1 :(得分:1)

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

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

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

(或者是最常用的包装方法)

答案 2 :(得分:1)

对于KotlinJS,您可以使用ts2kt将TypeScript定义翻译为Kotlin。它确实支持联盟类型,但可能并非所有情况都是完美的。有tests for unionTypes in ts2kt可以解释现在如何处理它们,并且在针对JavaScript平台时,您可以手动创建任何类似的东西。

issue #41 - to add better Union Type support的评论中提到了进一步的工作。最后,该主题至少有一个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作为返回类型代替union类型生成此Kotlin;在其他情况下重载方法签名以处理联合类型(我添加的一些评论):

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