如何表示参数可以扩展typescript中的字符串列表



我有一个接受string参数的方法。但是,我想稍微约束一下这个参数。因此,我用我想接受的字符串创建了一个并集类型

type Foo = 'a' | 'b';

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

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

我想做的是允许调用者传递其他字符串(除了ab(。但是,我希望它们在某种程度上扩展原始并集类型。

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中表达这种约束吗?

@jscalz的评论让我重新考虑了我的答案。

从经典OOP的角度来看,bar<T extends Foo>(arg: T)中对泛型参数的extends约束意味着T具有Foo更多的所有性质。因此,有了这个约束,您可以放心地在bar中假设arg的行为至少与Foo类似(并且具有相同的属性结构(。

然而,在您的情况下,T既不是class也不是interface,而是字符串文字的并集,这就是extends变得毫无意义的地方:

假设bar<T extends Foo>(arg: T)按照您的意愿工作(如OP中所述(,也就是说,T是位于Foo之上的字符串文字的超集。这意味着,在bar()函数中,您根本无法控制arg保持的值——它可以保持任何类型的值,您也可以使用任意

考虑到以上情况,控制它进入bar()的唯一机会是使用function bar(args: Bar),其中Bar = Foo | 'c'也允许您在不进行强制转换的情况下调用bar('c');


原始答案:


type Bar定义为交集类型似乎至少可以驯服typescript linting错误:type Bar = Foo & 'c';

下面我列出了typescript规范中的相关部分(至少在我看来(,这些部分定义了类型的交集实际上会导致extends约束所识别的"子类型-超类型"关系:

3.11.3子类型和超类型中说:

S是类型T的一个子类型,并且T是S的超类型,如果S相对于T没有多余的性质(3.11.5(,并且以下其中一个为真:

[…]

  • S是并集型,S的每个组成型都是T的一个亚型

此外,在3.11.4分配兼容性中(由我加粗(:

S是可赋值的到类型T,并且T是从S可赋值的,如果S相对于T没有多余的属性(3.11.5(,并且以下其中一个为真:

[…]

  • S是并集类型,并且S的每个组成类型都可分配给T

关于extends关键字,Typescript手册中指出了以下内容(我用粗体表示(:

出于实用目的,类型兼容性由赋值兼容性决定,即使在实现和扩展子句的情况下也是如此

在您的情况下,Foo等同于规范中的SBar是您的超类型(或超集(,等同于T规范。

但是,我不确定这个答案是否能满足您的要求,因为您也可以编写bar('x' as Bar);,尽管您的类型中没有包含"x",但编译器不会显示错误。

我认为你最好的办法就是简单地使用function bar(x: Bar)。这也允许您调用bar('c');

最新更新