如何将 URLSearchParams.get() 返回值的类型缩小为联合类型?
URL 中有一个搜索参数,如下所示:?mode=view
。 mode
的有效值应该是 'edit'
和 'view'
,因此我创建了一个 ModeTuple
类型并使用索引访问类型 ModeTuple[number]
将其转换为联合类型。
type ModeTuple = ['view', 'edit'];
const searchParams = new URLSearchParams();
const modes: ModeTuple = ['view', 'edit'];
const m1: ModeTuple[number] = modes.includes(searchParams.get('mode')) ? searchParams.get('mode') : 'view';
我想使用 modes.includes(...)
检查 mode
的值是否有效,然后将类型缩小为联合类型 'edit' | '查看'
。
出现错误:
“字符串”类型的参数不可分配给““视图”类型的参数 | “编辑”'
看来 Array.prototype.includes 方法不会将类型从 string
缩小到 “view” | “编辑”
成功。从JS代码逻辑来看,mode
值必须是'view'
或'edit'
。但 TSC 并不知道这一点。
<一href="https://www.typescriptlang.org/play?#code/C4TwDgpgBAsg9gEwgFQK5gDbQLxQNoDkAbgJYQDuBANFARAicAQLoDcAUOwMZwB2AzsCj8IAQwBOXABYAFCaIC2-KLl4UoAVQ BKAGQDKYybPlKAFAEoOPAUIWII-AFyx7aTDnzEylGnQZM2TmtBKAUARmd4JDcsPF5UBQAjCHFmFVD7fgA6El4uDFQkflMRCWk5cUVsgHMIYFMCOyQCc3MoAH5hQ3KTGrqGpogWqGcvCgIOIA" rel="nofollow noreferrer">TypeScript 游乐场
There is a search parameter in URL like this: ?mode=view
. The valid value of mode
should be 'edit'
and 'view'
, so I create a ModeTuple
type for it and convert it to union type using indexed access types ModeTuple[number]
.
type ModeTuple = ['view', 'edit'];
const searchParams = new URLSearchParams();
const modes: ModeTuple = ['view', 'edit'];
const m1: ModeTuple[number] = modes.includes(searchParams.get('mode')) ? searchParams.get('mode') : 'view';
I want to check if the value of mode
is valid using modes.includes(...)
, then narrow the type to union type 'edit' | 'view'
.
Got error:
Argument of type 'string' is not assignable to parameter of type '"view" | "edit"'
It seems Array.prototype.includes
method will NOT narrow the type from string
to "view" | "edit"
successfully. From the logic of the JS code, the mode
value must be 'view'
or 'edit'
. But TSC doesn't know that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
const m1: ModeTuple[number] = models.includes(searchParams.get('mode')) ? searchParams.get('mode') : 'view'; 不起作用有两个原因:
mode.includes
需要一个ModeTuple[number]
参数,但searchParams.get('mode')
返回string |空
。TypeScript 对缩小类型的流分析是有限的。即使 #1 不是问题,它也不会从
modes.includes(searchParams.get('mode'))
得知后续调用searchParams.get('mode) ')
将返回一个ModeTuple[number]
值。 (尤其是因为并非所有函数都是纯函数,因此 TypeScript 在一般情况下不能假设函数在使用相同参数调用两次时会返回相同的内容两次。)对于这样的事情,我喜欢从一个常量开始数组,然后从中派生类型:
这样,这些值仅列出一次,并且如果我需要添加一个等,我只有一个地方可以更改它们。
然后,您可以替换原始值
m1
代码如下:...但是我不喜欢那样做内联类型断言,因为它们很冗长并且重复它们给了我很多出错的机会。
相反,我更喜欢定义一个 类型谓词 (又名“类型保护”)我可以重用的函数:
那么你可以这样做:
或者你可以定义一个函数来执行它,如果你可能需要在多个地方执行它:
那么获取它只是:
游乐场链接
const m1: ModeTuple[number] = modes.includes(searchParams.get('mode')) ? searchParams.get('mode') : 'view';
won't work for two reasons:mode.includes
expects aModeTuple[number]
argument, butsearchParams.get('mode')
returnsstring | null
.TypeScript's flow analysis for narrowing types is limited. Even if #1 weren't an issue, it wouldn't know from
modes.includes(searchParams.get('mode'))
that a subsequent call tosearchParams.get('mode')
will return aModeTuple[number]
value. (Not least because not all functions are pure, so TypeScript can't assume in the general case that a function will return the same thing twice when called twice with the same arguments.)For things like this, I like to start with a constant array, then derive the types from it:
That way, the values are only listed once and I only have one place to change them if I need to add one, etc.
Then, you could replace your original
m1
code with:...but I don't like doing inline type assertions like that, because they're verbose and repeating them gives me multiple chances to get it wrong.
Instead, I prefer defining a single type predicate (aka "type guard") function that I can reuse:
Then you could do:
Or you could define a function to do it, if you may need to do it in more than one place:
Then getting it is just:
Playground link