类型对象的类型安全数组,没有任何类型脚本

时间:2020-01-13 10:14:30

标签: typescript generics

我有以下用例:我有一个高度可配置的UI组件,涉及泛型类型。我将此配置存储在一个数组中,允许我通过在其上进行映射来在UI中生成任意数量的配置。假设配置看起来像这样(简化的情况,它也是available in this Typescript playground):

.media {
    padding: 10px;
    background-color: #e9ecef;
    border-radius: 0.25rem;
    margin: 10px;
}
#record_left_content {
    float: left;
    margin-left: 20%;
}

#record_right_content {
    float: right;
    margin-right: 20%;
}

然后我的数组如下所示:

interface Config<T> {
  default: T;
  availableChoices: Array<T>
}

问题是:类型const configs: Array<Config<???>> = [ { default: 42, availableChoices: [1, 13, 42] }, { default: "a", availableChoices: ["a", "b"] } ] 应该是什么,以在所有单个元素中实现类型的一致性?我尝试使用???,但是它不能按应有的方式工作(说实话,这并不令人惊讶):

any

联合类型的工作原理几乎相同(除非它至少禁止其他类型):

// BAD
const configs: Array<Config<any>> = [
    { default: 42, availableChoices: [1, 13, 42] },
    { default: "a", availableChoices: [1] }  // passes type check (bad, element is of type Config<string>)
]

是否可以对数组的每个元素强制执行“相同类型参数”?据我所知,例如Scala允许使用// A LITTLE BETTER const configs2: Array<Config<string | number>> = [ { default: 42, availableChoices: [1, 13, 42] }, { default: "a", availableChoices: [1] }, // passes type check (bad) { default: "a", availableChoices: [1, "a"] }, // even this passes type check (worse, allows mixing up types in single element) { default: "a", availableChoices: [true] } // this fails (good, we want only string and numbers) ]

_

其他语言的解决方案和可能的解决方法是什么?

注意:在这种情况下,必须使用通用,因为真正的配置要复杂得多,并且涉及选择器和动作创建者)

1 个答案:

答案 0 :(得分:0)

最简单的方法是在Config类型级别使用联合类型

const configs: Array<Config<number> | Config<string>> = [
    { default: 42, availableChoices: [1, 13, 42] },
    { default: "a", availableChoices: ["a", "b"] }
]

类型Config<number> | Config<string>表示数组可以同时具有两种类型,但是Config规则在每种类型中都完全满足。

这意味着当您的default是数字时,availableChoices中也需要输入数字。

您尝试使用Config<number | string>是错误的,因为这种结合允许在defaultavailableChoices属性中使用字符串和数字。区别在于Config级别的并集将整个对象保留为一种类型。

在类型级别上,无法定义一些实用程序,该实用程序将确保Config不考虑任何联合类型。

我建议的是创建值构造函数,以消除创建多个类型声明的需要。考虑:

const makeConfig = <T>(a: Config<T>): typeof a => a

const configs = [
    makeConfig({ default: 1, availableChoices: [1, 13, 42] }),
    makeConfig({ default: "a", availableChoices: ["a", "b"] }),
]

编写更多,但是configs可以正确地推断为(Config<number> | Config<string>)[],类型声明为0。

相关问题