如何表达参数可以扩展打字稿中的字符串列表?

时间:2018-11-19 21:01:31

标签: typescript

我有一个采用string参数的方法。但是,我想稍微限制一下该参数。因此,我使用要接受的字符串创建了 union类型

type Foo = 'a' | 'b';

现在,我有一个简单的方法:

function bar(foo: Foo) {
    // do something with that string
}

我想做的是允许呼叫者传递其他字符串(除ab之外)。但是,我希望他们对原始联合类型进行 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中表达此约束?

1 个答案:

答案 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)