TypeScript 4.1 新特性:字符串模板類(lèi)型,Vuex 終于有救了?
TypeScript 4.1 快要發(fā)布了,老爺子 Anders Hejlsberg[1] 加入了一項(xiàng)重大更新,「字符串模板類(lèi)型」 的支持。昨天看到這個(gè)更新的我特別興奮,曾幾何時(shí),只要一遇到字符串拼接相關(guān)的類(lèi)型,TypeScript 就束手無(wú)策了,比如:
Vuex中加了namespace以后,dispatch一個(gè)mutation type會(huì)帶上前綴dispatch('cart/add')。lodash的get方法,可以對(duì)一個(gè)對(duì)象進(jìn)行get(obj, 'a.b.c')這樣的讀取。
現(xiàn)在 4.1 加入的這個(gè)新功能讓這一切都擁有了可能。
基礎(chǔ)語(yǔ)法
它的語(yǔ)法和 es 里的字符串模板很相似,所以上手成本也很低,先看幾個(gè)例子:
type?EventNameextends?string>?=?`${T}Changed`;
type?T0?=?EventName<'foo'>;??//?'fooChanged'
type?T1?=?EventName<'foo'?|?'bar'?|?'baz'>;??//?'fooChanged'?|?'barChanged'?|?'bazChanged'
type?Concatextends?string,?S2?extends?string>?=?`${S1}${S2}`;
type?T2?=?Concat<'Hello',?'World'>;??//?'HelloWorld'
字符串模板中的聯(lián)合類(lèi)型會(huì)被展開(kāi)后排列組合:
type?T3?=?`${'top'?|?'bottom'}-${'left'?|?'right'}`;
//?'top-left'?|?'top-right'?|?'bottom-left'?|?'bottom-right'
新增關(guān)鍵字
為了這個(gè)功能,老爺子在 TS 中新增了 uppercase, lowercase, capitalize, uncapitalize 這些關(guān)鍵字,用于對(duì)模板粒度字符串變量進(jìn)行處理。
type?Casesextends?string>?=?`${uppercase?T}?${lowercase?T}?${capitalize?T}?${uncapitalize?T}`;
type?T11?=?Cases<'bar'>;??//?'BAR?bar?Bar?bar'
其實(shí)很簡(jiǎn)單,就是提供了幾個(gè)處理方法:大寫(xiě)、小寫(xiě),首字母大寫(xiě),首字母小寫(xiě)。
配合 infer
特別強(qiáng)大的一點(diǎn)是,模板字符串可以通過(guò) infer 關(guān)鍵字,實(shí)現(xiàn)類(lèi)似于正則匹配提取的功能:
type?MatchPairextends?string>?=?S?extends?`[${infer?A},${infer?B}]`???[A,?B]?:?unknown;
type?T20?=?MatchPair<'[1,2]'>;??//?['1',?'2']
type?T21?=?MatchPair<'[foo,bar]'>;??//?['foo',?'bar']
通過(guò) , 分割左右兩邊,再在左右兩邊分別用一個(gè) infer 泛型接受推斷值 [${infer A},${infer B}],就可以輕松的重新組合 , 兩邊的字符串。
配合 ... 拓展運(yùn)算符和 infer遞歸,甚至可以實(shí)現(xiàn) Join 功能:
type?Joinextends?(string?|?number?|?boolean?|?bigint)[],?D?extends?string>?=
????T?extends?[]???''?:
????T?extends?[unknown]???`${T[0]}`?:
????T?extends?[unknown,?...infer?U]???`${T[0]}${D}${Join}`?:
????string;
type?T30?=?Join<[1,?2,?3,?4],?'.'>;??//?'1.2.3.4'
type?T31?=?Join<['foo',?'bar',?'baz'],?'-'>;??//?'foo-bar-baz'
實(shí)戰(zhàn)運(yùn)用
實(shí)現(xiàn) Vuex namespace 推斷:
type?VuexOptions?=?{
???namespace?:?N,
???mutations:?M,
}
type?Action?=?N?extends?string???`${N}/${keyof?M?&?string}`?:?keyof?M
type?Store?=?{
???dispatch(action:?Action):?void
}
declare?function?Vuex<M,?N>(options:?VuexOptions ):?Store<M,?N>
const?store?=?Vuex({
???namespace:?"cart"?as?const,
???mutations:?{
??????add()?{?},
??????remove()?{?}
???}
})
store.dispatch("cart/add")
store.dispatch("cart/remove")
前往 Playground[2] 嘗試一下~
實(shí)現(xiàn) lodash get 函數(shù):
type?PropTypeextends?string>?=
????string?extends?Path???unknown?:
????Path?extends?keyof?T???T[Path]?:
????Path?extends?`${infer?K}.${infer?R}`???K?extends?keyof?T???PropType?:?unknown?:
????unknown;
declare?function?get<T,?P?extends?string>(obj:?T,?path:?P):?PropType<T,?P>;
const?obj?=?{?a:?{?b:?{c:?42,?d:?'hello'?}}};
const?value?=?get(obj,?"a.b.c")
前往 Playground[3] 嘗試一下~
總結(jié)
TypeScript 4.1 帶來(lái)的這個(gè)新功能讓 TS 支持更多字符串相關(guān)的拼接場(chǎng)景,其實(shí)是特別實(shí)用的,希望各位看了以后都能有所收獲~
參考資料
Anders Hejlsberg: https://github.com/ahejlsberg
[2]Playground: https://www.typescriptlang.org/play?ts=4.1.0-pr-40336-8#code/C4TwDgpgBAagrhAHgeTMAlgewHYGcA8AsgDRQByAfFALxQDeAUFM9gIYC2EuYrAxhAH4AXOWJNm7OMFYYcuESQYBfBg1CQoAQV6zsRUpRrkoSYBGwATXFFzAATumwBzKAKgADACR0ySgPTeANYQIJgAZlCEUABkNvaOTkruUCLBoRGEqurQAMrAmHYQ+uRUtIzMUBbo3DK8ABYAFHy6Itq6xZQAlCIAbpjoFsqqFhC8ADashVBhcNg6WNiwCIgdFA2YaAvyS0iougQkJd1QeQVFh5SqvHLAcWdG8EgN5SwcXDz8IgBEvJPAX1BWNZrnhgGIKpJpPsRC8KoCLBYGp16FAlOC4VBCuxMD0IEiUSoKiolJ1VLYzgA6Ko1YD1Bo-P5+VgIr6k8mFKnVHi0xoMuzAPxYnEQVlAA
[3]Playground: https://www.typescriptlang.org/play?ts=4.1.0-pr-40336-8#code/C4TwDgpgBACgTgezAFXBAPMgNLAhsACyggA9gIA7AEwGcobg4BLCgcwD4oBeAKCn-qMWrYmUq08hKAH4oAVwoBrCggDuFKAC4+AmPiKly1OooggEAMyjIZ1gNp7CAXS07+jg2ONQABgBIAbxYLCDgoAGkAXwA6QODQqAAlSJ9bcNEjCVNzKxtZeCRUSEw7cKccRM5NeSUVdVcBGuU1CgBuHh4qCABjABtcOGgLBW7gJgQNVghgTBwYDPE6BmY2dgAKBAAjACtq7CgwfWqYAEpjxBQ0Wdh2dp5uiYYoLe3uKACoXGqPze-u6oALAAmHBUaoAcgIEF6vQQ4KgkURdweFCeADdcL05NAuFApsANjscAAiXDRTbRbrEk5AA
推薦閱讀
