关于typescript:使用-TypeScript-模板字符串类型

我的博客原文:https://blog.gplane.win/posts/ts-template-string-types.html

介绍

在明天的早些时候,Anders Hejlsberg 在 TypeScript 的仓库中发了一个 Pull Request:Template string types and mapped type as clauses。这个个性预计会在 4.1 版本中可用。

具体给 TypeScript 带来什么新个性,我就不在这里反复说了,Anders Hejlsberg 在 PR 中介绍得很分明。这篇文章次要探讨利用这个模板字符串类型,来对字符串字面量类型进行一些典型的字符串操作。

革除字符串的特定前缀

实现与剖析

JavaScript 的字符串中有一个实例办法 trimStart,它能够去掉字符串后面的空格字符。咱们将在 TypeScript 的类型层面上实现这个性能。代码如下:

type Whitespace = ' ' | '\n' | '\r' | '\t'

type TrimStart<S extends string, P extends string = Whitespace> =
  S extends `${P}${infer R}` ? TrimStart<R, P> : S

第 1 行的 Whitespace 类型定义了罕用的一些空格字符。当然 Unicode 中还定义了其它的一些空格字符,咱们依据须要往 Whitespace 这个联结类型前面补充就能够。

第 3 行至第 5 行就是 TrimStart 类型的定义。这个类型须要两个类型参数,其中 S 是要被解决的字符串,P 是要被搜寻并删除的前缀。这两个参数都指定 string 类型作为泛型束缚。另外 TypeScript 容许咱们为类型参数提供一个默认类型,在这里,类型参数 P 的默认类型是 Whitespace,示意在不指定要搜寻哪些字符串的时候,默认搜寻空格字符。

咱们利用 conditional types 来让 TypeScript 剖析字符串 S 是否匹配咱们指定的 pattern:以 P 为结尾,前面追随任意字符串,同时利用 infer 关键字将前面的字符串提取进去用作被返回的类型。

如果传入的字符串匹配该 pattern,则会递归地 trim 上来,直到不再匹配这个带有指定前缀的字符串为止。

如果传入的字符串没带有该前缀或者曾经实现前缀删除,就会将 S 类型原样返回。

利用

type String1 = '\t  \r  \n   value'
type Trimmed1 = TrimStart<String1>

type String2 = '---value'
type Trimmed2 = TrimStart<String2, '-'>

以上的例子中,Trimmed1Trimmed2 的类型都是 'value'

当不给 TrimStart 类型传入第二个类型参数时,默认应用 Whitespace 类型;若提供,则能够删除指定的前缀。

字符串替换

实现与剖析

这里我别离实现了单次替换和全副替换。代码如下:

type ReplaceOnce<Search extends string, Replace extends string, Subject extends string> =
    Subject extends `${infer L}${Search}${infer R}` ? `${L}${Replace}${R}` : Subject

type ReplaceAll<Search extends string, Replace extends string, Subject extends string> =
    Subject extends `${infer L}${Search}${infer R}` ? ReplaceAll<Search, Replace, `${L}${Replace}${R}`> : Subject

ReplaceOnce 类型和 ReplaceAll 类型须要三个类型参数:Search 类型是要被搜寻的字符串;Replace 类型用于找到 Search 后,替换掉原来的 SearchSubject 就是要被解决的字符串。

ReplaceOnce 类型和 ReplaceAll 类型很类似:都用到了 conditional types,而且条件还雷同。不同的是条件判断通过后返回的类型不同。

在下面的 conditional types 的条件中,咱们对 Subject 字符串进行 pattern 匹配:查看字符串中是否蕴含 Search 字符串。如果蕴含,则还利用 infer 关键字将位于 Search 右边、左边的字符串提取进去用于返回。须要留神的是,只管在咱们的 pattern 中 Search 在两头,但这并不意味着 Search 肯定要在两头才算匹配——放在结尾或开端也是能够的(放在开端时,可能存在某些 edge cases 不能被匹配,这应该是 TypeScript 的问题),而这时候 infer Linfer R 推断进去的类型是一个空字符串字面量类型,即 '' 类型。

如果字符串匹配咱们的 pattern,则利用传入的 Replace 字符串代替原来的 Search 字符串,同时应用之前提取进去的类型 L 和类型 R 来组成新的字符串:${L}${Replace}${R}

到这里,咱们曾经实现一次替换了。对于 ReplaceOnce 类型,当初就能够将刚刚生成的新字符串类型返回;而对于 ReplaceAll 类型,则将这个新的字符串类型作为 Subject 参数,再次传入 ReplaceAll 类型中而后递归上来,直到所有字符串都被替换。

利用

type String2 = 'process'
type Replaced1 = ReplaceOnce<'s', 'x', String2>
type Replaced2 = ReplaceOnce<'ss', 'x', String2>
type Replaced3 = ReplaceAll<'s', 'x', String2>

在下面的例子中,Replaced1 的类型是 'procexs'Replaced2 的类型是 'procex'Replaced3 的类型是 'procexx'。后果合乎预期。

查看是否蕴含指定的子字符串

实现与剖析

这个能够由下面的「字符串替换」简化而来:

type IsIncludes<Needle extends string, Haystack extends string> =
  Haystack extends `${infer L}${Needle}${infer R}` ? true : false

Needle 就是要查找的子字符串,Haystack 就是要被搜寻的字符串。conditional types 中的 pattern 与下面「字符串替换」中的 pattern 一样。最初依据匹配与否返回 true 类型或 false 类型即可。

利用

type String2 = 'process'
type Included = IsIncludes<'pro', String2>
type NotIncluded = IsIncludes<'pre', String2>

在下面的例子中,Included 的类型为 trueNotIncluded 的类型为 false


最初,这里有我写的一份代码,我把它放在 TypeScript 的 Playground 上。

另外,自己最近在寻找前端岗位的工作。分割邮箱:g-plane#hotmail.com

全文完。

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据