TypeScript添加了对模板字符串类型的支持

2020-09-01 20:55:25

模板字符串类型,这是字符串文字的一种形式,带有嵌入的泛型占位符,可以通过类型实例化用实际的字符串文字替换。

MAPPLED TYPE AS子句,提供转换映射类型中的属性名称的功能。

模板字符串类型是与模板字符串表达式等效的类型空间。与模板字符串表达式类似,模板字符串类型包含在反引号分隔符中,并且可以包含${T}形式的占位符,其中T是可分配给字符串、数字、布尔值或bigint的类型。模板字符串类型提供了连接文字字符串、将非字符串基元类型的文字转换为其字符串表示形式以及更改字符串文字的大小写的功能。此外,通过类型推断,模板字符串类型提供了字符串模式匹配和分解的简单形式。

占位符中的并集类型分布在模板字符串类型上。例如`[${A|B|C}]`解析为`[${A}]`|`[${B}]`|`[${C}]`。多个占位符中的并集类型解析为叉积。例如`[${A|B},${C|D}]`解析为`[${A},${C}]`|`[${A},${D}]`|`[${B},${C}]`|`[${B},${D}]`。

占位符中的String、Number、Boolean和Bigint文本类型会导致将占位符替换为文本类型的字符串表示形式。例如`[${';abc';}]`解析为`[abc]`,`[${42}]`解析为`42`。

占位符中的ANY、STRING、NUMBER、Boolean或Bigint类型中的任何一种都会使模板字符串解析为String类型。

在占位符中键入类型Never会导致模板字符串解析为Never。

类型EventName<;T扩展字符串>;=`${T}Changed`;类型Concat<;S1扩展字符串,类型S2扩展字符串>;=`${S1}${S2}`;类型ToString<;T扩展字符串|Number|Boolean|bigint>;=`${T}`;类型T0=EventName<;';foo';>;;//';fooo。|';bar';|';baz';>;;//';fooChanged';|';barChanged';|';bazChanged';type T2=conat<;&39;Hello';,';World';>;//';HelloWorld';type T3=`${';type T3=`${';下';}-${';左';|';右';}`;//';左上&39;|';|';左下&39;|';右下&39;键入T4=ToString<;';ABC';|42|true|-1234n&>;;//';ABC。|';42';|';true';|';-1234';

请注意,联合类型的交叉积分布可能会迅速升级为非常大且成本高昂的类型。另请注意,联合类型限制为少于100,000个成员,以下情况将导致错误:

Type digit=0|1|2|3|4|5|6|7|8|9,type Zip=`${digit}${digit}`;//错误。

模板字符串占位符可以选择在类型前指定大写、小写、大写或非大写修饰符。此修饰符更改整个替换字符串的大小写或替换字符串的第一个字符。例如:

类型GetterName<;T扩展字符串>;=`get${Capitalize T}`;类型Cases<;T扩展字符串>;=`${UPERCASE T}${LOWERCASE T}${CAPITALIZE T}${UNCAPITIZE T}`;类型T10=GetterName<;';FOO';>;//';getFoo';类型T11=Cases<;T12类型=案例<;&39;bar&39;>;;//';bar';

模板字符串类型都可以分配给字符串或子类型。此外,模板字符串类型`${T}`可分配给模板字符串类型`${C}`,并且是模板字符串类型`${C}`的子类型,其中C是T的字符串文字类型约束。例如:

函数test<;T扩展';foo';|';bar';>;(名称:`get${Capitalize T}`){let S1:string=name;let S2:';getFoo';|';getBar';=name;}。

类型推断支持从字符串文字类型到模板字符串类型的推断。要成功推断,目标模板字符串中的每个占位符必须由至少一个字符的跨度分隔,以指导匹配(换言之,无法推断为紧邻的占位符)。推理是通过非贪婪地从左到右加工每个跨度,并从跨度之间的子字符串推断到占位符类型来进行的。一些例子:

类型MatchPair<;S扩展字符串>;=S扩展`[${INFER A},${INFER B}]`?[A,B]:未知;type T20=MatchPair<;';[1,2]&39;>;;//[';1';,';2';]type T21=MatchPair<;;[foo,bar]';>;;//[';foo';,';bar';]type T22=MatchPair<;;//[';foo';,';bar';]type T22=MatchPair<;[1,2]';>;;//未知类型T23=MatchPair<;';[1,2]&39;>;;//未知类型T24=MatchPair<;';[1,2,3,4]&39;>;;//[';1';,';2,3,4';]

模板字符串类型可以与递归条件类型组合,以编写迭代重复模式的联接和拆分类型。

类型JOIN<;T扩展(string|number|boolean|bigint)[],D扩展字符串>;=T扩展[]?';';:t扩展[未知]?`${T[0]}`:t扩展[未知,...。推断U]?`${T[0]}${D}${Join<;U,D>;}`:string;type T30=Join<;[1,2,3,4],';.';>;;//';1.2.3.4';type T31=Join<;[';foo';,';bar';,';baz&39;],';-';>;;//';foo-bar-baz&39;type T32=加入<;[],';.&39;>;;//';';

类型Split<;S扩展字符串,D扩展字符串>;=string扩展S?字符串[]:s扩展`${INFER T}${D}${INFER U}`?[T,...。Split<;U,D>;]:[s];type T40=Split<;';,';,';;';>;;//[';foo';]type T41=Split<;';foo.bar.baz';,';.';>;//[';foo';,&。Bar';,';Baz';]类型T42=拆分<;任意,';.';>;;//字符串[]。

例如,递归推理功能可以用于强类型函数,这些函数使用虚线路径和JavaScript框架中有时使用的模式访问属性。

键入PropType<;T,路径扩展字符串>;=字符串扩展路径?未知:路径扩展了T的键?T[路径]:路径扩展`${INFER K}。${推断R}`?K扩展了T?PropType<;T[K],R>;:未知:未知;声明函数getPropValue<;T,P扩展字符串>;(obj:T,path:P):PropType<;T,P>;;声明const s:string;const obj={a:{b:{c:42,d:';hello';};getPropValue(obj,';a。//{b:{c:number,d:string}}getPropValue(obj,';a.b';);//{c:number,d:string}getPropValue(obj,';a.b.d';);//string getPropValue(obj,';a.b.x';);//未知getPropValue(obj,s);//未知。

使用此PR,映射类型支持可选的AS子句,通过该子句可以指定生成的属性名称的转换:

其中N必须是可赋值给字符串的类型。通常,N是转换P的类型,例如在占位符中使用P的模板字符串类型。例如:

键入getters<;T>;={[P in keyof T&;string as`get${Capitalize P}`]:()=>;T[P]};type T50=getters<;{foo:string,bar:number}>;;//{getFoo:()=>;string,getBar:()=>;number}

上面,Key of T&;字符串交集是必需的,因为KeyOf T可能包含不能使用模板字符串类型转换的符号类型。

当AS子句中指定的类型解析为Never时,不会为该键生成任何属性。因此,AS子句可以用作筛选器:

类型方法<;T>;={[T的键中的P作为T[P]扩展函数?P:从不]:t[P]};type T60=方法<;{foo():number,bar:boolean}>;;//{foo():number}。

当AS子句中指定的类型解析为文字类型的联合时,将生成多个具有相同类型的属性:

Type DoubleProp<;T>;={[P in keyof T&;string as`${P}1`|`${P}2`]:t[P]}type t70=DoubleProp<;{a:string,b:number}>;;//{a1:string,a2:string,b1:number,b2:number}