采用两个数组或两个对象的TypeScript泛型函数,而不是混合

时间:2016-06-06 18:14:59

标签: typescript

我在TypeScript中编写extend函数,可以:

  • 取两个对象,在这种情况下,它会使用第二个的键/值更新第一个。
  • 取两个数组,在这种情况下,它会将第二个元素追加到第一个数组。

  • extend({a: 1}, {b: 2}) → {a: 1, b: 2}
  • extend([1], [2]) → [1, 2]

此函数应该采用两个数组或两个对象,而不是每个对象中的一个。

我正在尝试为它提出正确的类型签名。理想情况下它会是这样的:

function extend<A, B, StrOrNum extends (string|number)>(
    a: {[key: StrOrNum]: A},
    b: {[key: StrOrNum]: B}): {[key: StrOrNum]: A&B} {
  ..
}
然而,

tsc抱怨索引签名必须是stringnumber

[ts] An index signature parameter type must be 'string' or 'number'.
(parameter) key: StrOrNum extends string | number

如果我正在编写一个类型定义文件,我只需定义该函数的两个重载。我在实施时可以做类似的事情吗?或者这个函数是不连贯的 - 这是类型系统告诉我应该将它分成extendObjectextendArray函数的方式吗?

1 个答案:

答案 0 :(得分:0)

您可以使用选项界面执行类似的操作:

interface ObjectOptions<T> { a: {[key: string]: T}, b: {[key: string]: T} }
interface ArrayOptions<T> { a: Array<T>; b: Array<T>; }
function extend<T>(params: ObjectOptions<T>|ArrayOptions<T>) { }
extend({a:[1],b:{k:1}}); // error

在某些情况下,您还可以使用定义重载的接口Foo来扩展名为Foo的类,但这很少是个好主意。所有这些都比仅具有两个不同的函数更麻烦,例如concat用于数组,而merge用于对象。

  

或者这个功能是不连贯的 - 这是类型系统告诉我的方式......

是。基于对象的映射是对象的映射,但是数组也是对象的映射。您的函数应该始终如一地处理这两个映射 - 您对数组的操作不应该产生:

extend([1], [2]) → [1, 2]

但是:

extend([1], [2]) → [2]
extend([1, 2], [7, undefined, 8]) → [7, 2, 8]

对于新的TypeScript代码,如果您遇到重载问题,请选择创建两种不同的方法,而不是尝试将类型检查破解为单个方法。 (最大的好处是无忧重构)