查找由模板文字类型的任何可能组合组成的打字脚本类型 [英] Looking for a TypeScript type that consists of any possible combination of Template Literals Types

查看:15
本文介绍了查找由模板文字类型的任何可能组合组成的打字脚本类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于我的项目,我需要提供一种打字类型,即所谓的CardSize。

此类型可以采取多种形式。它可以是静态值、响应值(特定于断点),也可以是由空格分隔的二者的组合。

可能的(单数)值如下:

type CardSize =
'compact' |
'normal' |
'compact@small' |
'compact@medium' |
'compact@large' |
'normal@small' |
'normal@medium' |
'normal@large';

我最终想要的类型如下所示:

type CardSize = 
'compact' | 
... |
'normal@large' |
'compact normal@medium' |
'compact compact@small normal@medium' | 
'compact@small normal@large' etc.

第一步似乎是使用模板文字类型,所以我介绍了所有单数类型:

type CardSize = Size | `${Size}@${Breakpoint}`;

接下来,我尝试寻找可能值的任何组合的排列,但到目前为止还没有任何结果。

如果我能以某种方式将这两个约束设置到位,那就太好了:

将可能的组合数量限制为同时只分配一个特定的断点值(例如,'compact@small''normal@small不在同一字符串中)

其次,如果排列的顺序是不相关的,那就好了。我认为以下几点是相同的:

const size: CardSize = 'compact@small @normal@large';
const size: CardSize = 'normal@large compact@small';

有人知道如何实现这种类型的排列吗?即使这意味着没有这两个约束,这也是一个很大的帮助!

Re:我意识到对于我试图实现的目标来说,置换类型有点过头了。我可以强制CardSize的类型安全而不依赖| string作为备用吗?

推荐答案

您绝对可以生成union type字符串值的排列/组合,通过template literal types递归连接。当然,随着要排列和组合的元素数量的增加,排列和组合的数量会迅速增加。TypeScrip只能处理数万个元素的构建联合,当您接近这一点时,编译器的性能往往会受到影响。因此,此方法仅适用于少量元素。

您的CardSize示例很好用,因为您只有两个大小和四个断点:

type CardSize = BuildCardSizes<'compact' | 'normal', '' | '@small' | '@medium' | '@large'>

其中BuildCardSizes<S, B>是一个适当定义的类型函数,它允许您随意使用S中的任何内容,但最多只允许您使用B的元素一次。我是这样定义它的:

type BuildCardSizes<S extends string, B extends string, BB extends string = B> =
    B extends any ? (`${S}${B}` | `${S}${B} ${BuildCardSizes<S, Exclude<BB, B>>}`) : never;
这样做的目的是获取断点的联合B,并使用distributive conditional type将其拆分成其组成成员。这是B extends any ? (...) : never部分,在圆括号中,B只是该并集的单个元素。请注意,我们还需要完整的工会。TypeScrip并不容易做到这一点,所以我使用了另一个类型参数BB,它将defaults替换为原始的B。在下文中,B表示当前断点并集的某些特定元素,而BB表示断点当前并集的完整元素。

因此,对于每个B,可接受的卡片大小要么是`${S}${B}`,即S的某个元素与特定元素B的串联;要么是`${S}${B} ${BuildCardSizes<S, Exclude<BB, B>>}`,即后面跟着一个空格,然后BuildCardSizes<S, Exclude<BB, B>>...这是使用相同S但从完整元素列表BB中删除B后获得的卡大小集。

让我们在您的示例上进行测试:

/* type CardSize = "compact" | "normal" | "compact@small" | "normal@small" | "compact@medium" | "normal@medium" |
"compact@large" | "normal@large" | "compact@medium compact@large" | "compact@medium normal@large" |
"normal@medium compact@large" | "normal@medium normal@large" | "compact@large compact@medium" |
"compact@large normal@medium" | "normal@large compact@medium" | "normal@large normal@medium" |
"compact@small compact@medium" | "compact@small normal@medium" | "compact@small compact@large" |
"compact@small normal@large" | "compact@small compact@medium compact@large" |
"compact@small compact@medium normal@large" | "compact@small normal@medium compact@large" |
"compact@small normal@medium normal@large" | "compact@small compact@large compact@medium" |
"compact@small compact@large normal@medium" | "compact@small normal@large compact@medium" |
"compact@small normal@large normal@medium" | "normal@small compact@medium" | "normal@small normal@medium" |
"normal@small compact@large" | "normal@small normal@large" | "normal@small compact@medium compact@large" |
"normal@small compact@medium normal@large" | "normal@small normal@medium compact@large" |
"normal@small normal@medium normal@large" | "normal@small compact@large compact@medium" |
"normal@small compact@large normal@medium" | "normal@small normal@large compact@medium" |
"normal@small normal@large normal@medium" | "compact@large compact@small" | "compact@large normal@small" |
"normal@large compact@small" | "normal@large normal@small" | "compact@medium compact@small" |
"compact@medium normal@small" | "compact@medium compact@small compact@large" | ... */
呃,哇,编译器对这个联合没有问题...checks notes...632个元素,但它太大了,我无法在这个答案中写出或完全检查。无论如何,您可以从上面看到大小被重用,但断点没有。

我们抽查一下:

c = 'normal compact@small' // okay
c = 'compact@small normal' // okay
c = 'compact@small normal normal@large compact@medium' // okay
c = 'normal@small normal@medium normal@large normal' // okay

c = 'compact@small normal@small' // error
c = 'compact normal' // error
c = 'normal@small normal@medium normal@large normal normal@big' // error
c = '' // error

看起来不错!

正如我在注释中提到的,对于更多的元素,还有其他方法;您不是生成所有可能可接受的值的特定联合,而是使用泛型约束来check确定某个给定值是可接受的。然而,它更复杂,超出了这个问题的范围。

Playground link to code

这篇关于查找由模板文字类型的任何可能组合组成的打字脚本类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆