我有一个采用string
参数的方法。但是,我想稍微限制一下该参数。因此,我使用要接受的字符串创建了 union类型:
type Foo = 'a' | 'b';
现在,我有一个简单的方法:
function bar(foo: Foo) {
// do something with that string
}
我想做的是允许呼叫者传递其他字符串(除a
和b
之外)。但是,我希望他们对原始联合类型进行 extend 排序。
function bar<T extends Foo>(str: T) {
// do something with that string
}
type Bar = Foo | 'c';
// this doesn't work: Argument of type 'Bar' is not assignable to parameter of type 'Foo'. Type '"c"' is not assignable to type 'Foo'.
bar('c' as Bar);
有没有办法在TypeScript中表达此约束?
答案 0 :(得分:2)
@jscalz的评论让我重新考虑了答案。
从经典的OOP角度来看,extends
中对通用参数的bar<T extends Foo>(arg: T)
约束意味着T
拥有Foo
和更多。因此,有了这个约束,您可以放心地在bar
中假设arg
的行为至少类似于Foo
(并且具有相同的属性结构)。
但是,在您的情况下,T
既不是class
也不是interface
,而是字符串常量的组合,这就是{{1 }}变得毫无意义:
让我们假设extends
可以按您希望的方式工作(如您的OP中所述),这意味着bar<T extends Foo>(arg: T)
是T
之上的字符串文字的超集。这意味着在您的Foo
函数中,您根本无法控制bar()
所保存的值–它可以保存任何种值,您也可以使用< em>任何。
鉴于上述情况,控制进入arg
的唯一机会是使用bar()
,其中function bar(args: Bar)
还可让您呼叫Bar = Foo | 'c'
而无需
原始答案:
将bar('c');
定义为intersection type似乎至少可以解决打字稿掉毛错误:type Bar
。
下面,我从打字稿规范中列出相关部分(至少据我所知),这些部分定义了类型的交集实际上导致了“子类型-超类型”关系,该关系由type Bar = Foo & 'c';
约束识别: / p>
在3.11.3 Subtypes and Supertypes中说:
S是T类型的子类型,并且T是S的超类型,如果S相对于T(3.11.5)不具有多余的属性,并且下列条件之一为真:
[...]
- S是联合类型,S的每个组成类型都是T的子类型。
此外,3.11.4 Assignment Compatibility(由我加粗显示):
S是可分配的到类型T,并且T可从S分配,如果S相对于T没有多余的属性(3.11.5),并且以下条件之一为真:>
[...]
- S是联合类型,并且每个S的组成类型都可以分配给T。
关于extends
关键字,“打字稿”手册指出以下内容(由我加粗显示):
出于实际目的,类型兼容性由分配兼容性决定,即使在实现和扩展子句的情况下也是如此。
在您的情况下,extends
等同于规范中的Foo
,而S
是您的超类型(或超集),等同于Bar
规范。
但是,我不确定此答案是否满足您的要求,因为您也可以编写T
,并且即使类型中未包含'x',编译器也不会显示错误
我认为您最好的选择就是简单地使用bar('x' as Bar);
。然后,它还允许您呼叫function bar(x: Bar)