我正在寻找一种使代码更具类型安全性的方法,并希望在将某些类型传递给泛型函数时定义它们之间的紧密关系。
例如,对于给定的一组类型:
interface FooParam {}
interface FooReturn {}
interface BarParam {}
interface BarReturn {}
和以下功能:
function action<T, R>(foo: T): R
我想将FooParam
与FooReturn
紧密绑定,并将BarParam
与BarReturn
绑定,因此,仅当传递了一对关联类型时,编译器才允许调用分别为T
和R
,并返回错误。
action<FooParam, FooReturn>(...) // bound types, OK
action<BarParam, BarReturn>(...) // bound types, OK
action<FooParam, BarReturn>(...) // types are not bound, ERROR
action<FooParam, string>(...) // types are not bound, ERROR
实际上,我已经通过定义两个基本接口来实现上述目的,这些接口随后将用作对通用类型的约束:
interface Param {}
interface Return<T extends Param>{
_typeGuard?: keyof T
}
interface FooParam extends Param {}
interface FooReturn extends Return<FooParam> {}
interface BarParam extends Param {}
interface BarReturn extends Return<BarParam> {}
function action<T extends Param, R extends Return<T>>(foo: T): R
但是,这似乎更像是一种解决方法,而不是一个干净的解决方案,尤其是考虑到_typeGuard?: keyof T
字段,该字段仅存在,因此T
实际上很重要,并且被检查而不被忽略。另一个缺点是,每种类型都必须扩展我的自定义接口之一,有时候这是不可能的。
是否有更好,更通用的方法来获得所描述的功能?
答案 0 :(得分:3)
您可以使用通用类型和推断。如果您的要求允许这样做,那么比从基本接口扩展每种类型都容易。此解决方案将所有链接放在一个位置,因此有其自身的缺点,但是如果您不能更改原始类型,对我来说似乎可以:
type Return<T> =
T extends BarParam ? BarReturn :
T extends FooParam ? FooReturn :
never;
您可以在操作Playground中看到它
答案 1 :(得分:1)
听起来比泛型更像是code。
{
"query": {
"bool": {
"must": {
"term": {
"event_type": "my_event_type"
}
},
"should": [
{
"terms": {
"event_type": [
"my_event_type1",
"my_event_type2",
"my_event_type3"
]
}
}
]
}
}
}
在这里,我不建议在泛型中使用条件类型。
答案 2 :(得分:0)
我将基于链接类型将耦合的接口制成泛型:
interface Foo {}
interface Bar {}
interface Param<T> {
}
interface Return<T> {
}
interface FooParam extends Param<Foo> {
}
interface FooReturn extends Return<Foo> {
}
interface BarParam extends Param<Bar> {
}
interface BarReturn extends Return<Bar> {
}
function action<T>(foo: Param<T>): Return<T> {
...
}