带占位符的模板文字类型的子类型规则是什么(如`${number}em`)?它不在手册的Template Literal Types部分中,我在搜索中也没有找到任何与它相关的东西,尽管我可能在哪里错过了它;搜索它是很棘手的.

我之所以这样问,是因为我最近惊讶地发现`${number}` extends `${string}`是真的.经过反思,我有一个合理的 idea 为什么会这样,但我正在寻找确认和细节,如果我是对的,或者如果我错了,我正在寻找正确的解释.(作为背景,这是在我试图向自己证明我对this question的答案是可靠的时候提出的.)

我的 idea 是:

  • 如果匹配S的字符串也匹配T,则模板文字类型S是模板文字类型T的子类型.

对于我的`${number}` extends `${string}`示例也是如此,因为匹配`${number}`(如"123")的任何字符序列也将匹配`${string}`.

这似乎也是the general rule"...any term of type 101 can safely be used in any context where a term of type 102 is expected..."之间的合理契合.

这是正确的吗?如果是这样,是否还有进一步的细微差别?如果不是,正确的定义是什么?

顺便说一句,以下是我用来测试直觉的一系列有点曲折的测试:

type A = `${number}` extends `${number}` ? true : false;
//   ^?
// true, since they're the same thing, so yeah, it's a match

type B = `${number}` extends `${number|string}` ? true : false;
//   ^?
// true, anything matching `${number}` would also match `${number|string}`

type C = `${number}` extends `${string}` ? true : false;
//   ^?
// true, which makes sense for a template literal even though number isn't a subtype of
// string, because anything matching `${number}` would also match `${string}` --
// that is, a series of digits is not just a valid number, but also a valid string

type D = `${string}` extends `${number}` ? true : false;
//   ^?
// false, because the converse isn't true; not all sequences of characters are
// valid numbers

type E = `${number|string}` extends `${number}` ? true : false;
//   ^?
// false - same as D, basically

type F = `${number}` extends `${string}${number}` ? true : false;
//   ^?
// false because something matching `${number}` wouldn't match `${string}${number}`

type G = `${string}${number}` extends `${string}${number}` ? true : false;
//   ^?
// true, they're the same thing

type H = `${number}${string}` extends `${string}${number}` ? true : false;
//   ^?
// false, for the same reason as D and E

type I = `${number}x` extends `${string}x` ? true : false;
//   ^?
// true - basically the same as C, just with an x on it

type J = `${number}x` extends `${string}y` ? true : false;
//   ^?
// false because something matching `${number}x` wouldn't match `${string}y`

Playground link

推荐答案

microsoft/TypeScript#43361中实现了带有占位符的template literal types的赋值(具有像`abc${string}ghi`中的string这样的宽类型或像T extends `abc${infer U}ghi` ? U : never中的infer U这样的不确定类型).这就是对这一现象的权威性答案.

从概念上讲,是的,当类型X的每个值都可以安全地赋给类型Y的变量时,就是X extends Y.因此,你的直觉是正确的,并解释了大部分正在发生的事情.


只是带占位符的模板文字类型并不总是按照某些人的预期行事.

例如,当两个占位符相邻时,第一个占位符与输入中的一个字符完全匹配.所以"a"`a${string}${string}`不匹配:

type Hmm = "a" extends `a${string}${string}` ? true : false
//   ^? type Hmm = false

但只由string个重复占位符组成的模板文字折叠为string,因此"" does`${string}${string}`匹配.请参见microsoft/TypeScript#57355.

type Wha = "" extends `${string}${string}` ? true : false
//   ^? type Wha = true

number占位符并不是指"当您使用模板文字字符串序列化number时得到的那些字符串";相反,它指的是"任何可以被成功解析为number的东西",这也会导致奇怪的行为.请参见microsoft/TypeScript#57404this comment on a related issue microsoft/TypeScript#41893:

type Oops = "a       0" extends `a${number}` ? true : false
//   ^? type Oops = true

因此,虽然TypeScrip或多或少遵循这样的规则:"如果X可赋值给Y,那么X extends Y ? true : false就是true,有时当X可赋值给Y时,这并不明显.

Playground link to code

Typescript相关问答推荐

如何为ViewContainerRef加载的Angular组件实现CanDeactivate保护?

使用React处理Websocket数据

如何缩小变量访问的对象属性范围?

输入元素是类型变体的对象数组的正确方法是什么?'

我想创建一个只需要一个未定义属性的打字脚本类型

在包含泛型的类型脚本中引用递归类型A<;-&B

访问继承接口的属性时在html中出错.角形

如何使用WebStorm调试NextJS的TypeScrip服务器端代码?

为什么在这个例子中,我把缺少的属性添加到对象中时,TypeScrip没有拾取,如何修复?

使用Dockerfile运行Vite React应用程序时访问env变量

类型脚本映射类型:从对象和字符串列表到键值对象

如何按属性或数字数组汇总对象数组

判断映射类型内的键值的条件类型

从以下内容之一提取属性类型

TypeScrip:从嵌套的对象值创建新类型

VUE 3类型';字符串';不可分配给类型';参考<;字符串&>

基于泛型的类型脚本修改类型

如何在TypeScrip中使用数组作为字符串的封闭列表?

换行TypeScript';s具有泛型类型的推断数据类型

使用react+ts通过props传递数据