我有以下用例:我有一个高度可配置的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)
]
:
_
其他语言的解决方案和可能的解决方法是什么?
注意:在这种情况下,必须使用通用,因为真正的配置要复杂得多,并且涉及选择器和动作创建者)
答案 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>
是错误的,因为这种结合允许在default
和availableChoices
属性中使用字符串和数字。区别在于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。