typescript - 我如何表达一个参数可以扩展打字稿中的字符串列表?
问题描述
我有一个带string
参数的方法。但是,我想稍微限制该参数。所以,我用我想接受的字符串创建了一个联合类型:
type Foo = 'a' | 'b';
现在,我有一个简单的方法:
function bar(foo: Foo) {
// do something with that string
}
我想要做的是允许调用者传递其他字符串(除了a
and b
)。但是,我希望他们能够扩展原始联合类型。
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 角度来看,对泛型参数的extends
约束bar<T extends Foo>(arg: T)
将意味着T
拥有 的所有属性Foo
以及更多属性。因此,有了这个约束,您可以放心地假设您bar
的arg
行为至少相似Foo
(并且具有相同的属性结构)。
但是,在您的情况下,T
它既不是 a 也不是class
aninterface
而是字符串文字的联合,这就是extends
变得毫无意义的地方:
让我们假设按照您的bar<T extends Foo>(arg: T)
意愿工作(如您的 OP 中所述),意思是,T
是Foo
. 这意味着在你的bar()
函数中你根本无法控制哪些值arg
持有——它可能持有任何类型的值,你也可以使用any。
鉴于上述情况,您控制其进入方式的唯一机会bar()
是使用function bar(args: Bar)
,Bar = Foo | 'c'
这也允许您在bar('c');
不强制转换的情况下调用。
原答案:
定义type Bar
为交集类型似乎至少驯服了打字稿 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 手册指出以下内容(由我加粗):
出于实际目的,类型兼容性由赋值兼容性决定,即使在 implements 和 extends 子句的情况下也是如此。
在您的情况下Foo
,等同S
于规范,并且Bar
是等同于规范的超类型(或超集)T
。
但是,我不确定这个答案是否让您满意,因为您也可以编写bar('x' as Bar);
并且编译器不会显示错误,尽管您的类型中没有包含“x”。
我认为您最好的方法是简单地使用function bar(x: Bar)
. 然后还允许您致电bar('c');
推荐阅读
- c# - 如何在Castle Windsor中批量注册没有BasedOn方法的接口?
- reactjs - 如何在反应中正确获得axios响应?
- linux - 如何从函数调用值到shell脚本
- javascript - 在javascript中捕获网页上的键盘输入
- ios - 当我单击 xcode 中的单元格时,如何在 rightBarButtonItem 中放置不同的图像?
- dart - 使用多个 Dart SDK 版本的推荐方法是什么?
- angular - 使用 fileuri 无法使用离子图像预览
- java - 从 JSON/String 文件中获取特定的 JSON 属性
- javascript - 如何在使用 pywb 归档时单击带有 selenium 的按钮
- firebase - Firebase Cookie 未保存