【问题标题】:TypeScript generic function that takes two arrays or two objects, not a mixTypeScript 通用函数,它接受两个数组或两个对象,而不是混合
【发布时间】:2016-06-07 03:50:19
【问题描述】:

我正在使用 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 函数的方式?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您可以使用选项接口做类似的事情:

    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 代码,如果您遇到重载问题,最好创建两个不同的方法,而不是尝试将类型检查破解为单个方法。 (最大的好处是轻松重构)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-31
      • 2016-10-31
      • 1970-01-01
      • 1970-01-01
      • 2013-12-13
      • 1970-01-01
      • 2022-01-15
      • 2019-06-10
      相关资源
      最近更新 更多