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

How to represent multiple types (union types) when targeting JavaScript

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

下面是一个函数示例:

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

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

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

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

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

(或者像 kevinmost 建议的包装方法)

这不起作用,因为 T 不能表示为 StringNumberBoolean 交集的某种类型。

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

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

对于 KotlinJS,您可以使用 ts2kt to translate your TypeScript definitions to Kotlin. It does support Union Types but maybe not all cases are perfect. There are tests for unionTypes in ts2kt 来阐明它们现在的处理方式,并且您可以在针对 JavaScript 平台时对您手动创建的任何内容执行类似的操作。

issue #41 - to add better Union Type support. Lastly there is at least one discussion thread 的评论中提到了进一步的工作,主题表明:

In JS and TS in most cases union types used as the alternative to overloading, so in the near future, we going to use overloading for that when it possible. Also,​ we think about providing the additional way to specify union types for native declarations.

还有另一个 Stack Overflow 问题讨论了这个问题并提供了一些当前选项: 其答案在所有 Kotlin 目标平台上都有效。

特别是对于 JavaScript 目标,您可以考虑使用正在使用此类型的 dynamic type. I see at least 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 作为 return 类型代替联合类型生成此 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