第 79 期 - TypeScript 字符串操作:模板字面量类型的应用
摘要
文章阐述了 TypeScript 4.1 版本后的模板字面量类型,通过联合类型、infer 关键字和递归,展示了在字符串操作中的应用,如定义类型、提取部分内容、替换字符等,并修正操作中的错误。
一、TypeScript 的模板字面量类型基础示例
在 TypeScript 4.1 版本后,可以使用模板字面量语法操作字符串。例如定义InternalRoute
类型为/${string}
,这样函数goToRoute
的参数route
只能接收以/
开头的字符串,否则会报错。这展示了模板字面量类型在简单的字符串类型定义上的应用。
二、模板字面量类型中的联合类型
- 可以在模板字面量类型中使用联合类型来扩展成更大的联合类型。例如
EntityAttributes
类型定义为${'post' | 'user'}${'Id' | 'Name'}
,其结果是'postId' | 'userId' | 'postName' | 'userName'
。这体现了联合类型在模板字面量类型中的组合效果。
三、模板字面量类型中的 infer 关键字
- 可以在模板字面量中使用
infer
关键字。如GetLastName
类型定义中,TFullName extends
${infer TFirstName} ${infer TLastName}? TLastName : never
,对于像Matt Pocock
这样有空格分隔的字符串,infer
会将其拆分为类型变量TFirstName
和TLastName
,然后通过? TLastName
返回最后一个名字。例如type Pocock = GetLastName<'Matt Pocock'>
,结果为"Pocock"
。 - 对于更复杂的需求,如将名字中的空格替换为破折号。定义
ReplaceSpaceWithDash
类型,TFullName extends
${infer TFirstName} ${infer TLastName}?
${TFirstName}-${TLastName}: never
,例如type Name = ReplaceSpaceWithDash<'Emmylou Harris'>
,结果为"Emmylou - Harris"
。 - 为了让代码更通用,对类型变量重命名,将
TFullName
改为TString
,TFirstName
改为TPrefix
,TLastName
改为TSuffix
。
四、实现更通用的字符串替换类型
- 定义
Replace
类型来实现更通用的字符串替换,type Replace<TString extends string, TToReplace extends string, TReplacement extends string>
,当TString extends
${infer TPrefix}${TToReplace}${infer TSuffix}时,返回
${TPrefix}${TReplacement}${TSuffix},否则返回
never。例如
type DashName = Replace<'Matt Pocock', ' ', '-'>,结果为
"Matt - Pocock"`。 - 但是这个类型存在两个问题,一是如果没有找到要替换的字符串会返回
never
,这是不正确的,修改后的Replace
类型在没有找到要替换的字符串时返回传入的字符串。例如type Result = Replace<'Matt', ' ', '-'>
,结果为"Matt"
。 - 第二个问题是只替换一次,如果有多个要替换的字符串实例,后面的将被忽略。例如
type DashCaseName = Replace<'Matt Pocock III', ' ', '-'>
,结果为"Matt - Pocock III"
。
五、通过递归解决多次替换问题
- 定义
StringReplace
类型,通过递归调用解决多次替换的问题。type StringReplace<TString extends string, TToReplace extends string, TReplacement extends string>
,当TString extends
${infer TPrefix}${TToReplace}${infer TSuffix}时,返回
${TPrefix}${TReplacement}${StringReplace<TSuffix, TToReplace, TReplacement>},否则返回
TString。例如
type Result = StringReplace<'Matt Pocock III', ' ', '-'>,结果为
"Matt - Pocock - III"`。 - 在递归过程中,要注意避免无限循环。以
StringReplace<"Matt Pocock III", " ", "-">
为例,第一次返回Pocock III
,第二次返回III
,最后因为找不到" "
,直接返回TString
(这里是"III"
),从而结束递归循环。
扩展阅读
Made by 捣鼓键盘的小麦 / © 2025 Front Talk 版权所有