TypeScript 4.1 新特性:字符串模板類型,Vuex 終于有救了?
TypeScript 4.1 快要發(fā)布了,老爺子 Anders Hejlsberg[1] 加入了一項重大更新,「字符串模板類型」 的支持。昨天看到這個更新的我特別興奮,曾幾何時,只要一遇到字符串拼接相關的類型,TypeScript 就束手無策了,比如:
Vuex中加了namespace以后,dispatch一個mutation type會帶上前綴dispatch('cart/add')。lodash的get方法,可以對一個對象進行get(obj, 'a.b.c')這樣的讀取。
現(xiàn)在 4.1 加入的這個新功能讓這一切都擁有了可能。
基礎語法
它的語法和 es 里的字符串模板很相似,所以上手成本也很低,先看幾個例子:
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)合類型會被展開后排列組合:
type?T3?=?`${'top'?|?'bottom'}-${'left'?|?'right'}`;
//?'top-left'?|?'top-right'?|?'bottom-left'?|?'bottom-right'
新增關鍵字
為了這個功能,老爺子在 TS 中新增了 uppercase, lowercase, capitalize, uncapitalize 這些關鍵字,用于對模板粒度字符串變量進行處理。
type?Casesextends?string>?=?`${uppercase?T}?${lowercase?T}?${capitalize?T}?${uncapitalize?T}`;
type?T11?=?Cases<'bar'>;??//?'BAR?bar?Bar?bar'
其實很簡單,就是提供了幾個處理方法:大寫、小寫,首字母大寫,首字母小寫。
配合 infer
特別強大的一點是,模板字符串可以通過 infer 關鍵字,實現(xiàn)類似于正則匹配提取的功能:
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']
通過 , 分割左右兩邊,再在左右兩邊分別用一個 infer 泛型接受推斷值 [${infer A},${infer B}],就可以輕松的重新組合 , 兩邊的字符串。
配合 ... 拓展運算符和 infer遞歸,甚至可以實現(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'
實戰(zhàn)運用
實現(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] 嘗試一下~
實現(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] 嘗試一下~
總結
TypeScript 4.1 帶來的這個新功能讓 TS 支持更多字符串相關的拼接場景,其實是特別實用的,希望各位看了以后都能有所收獲~
參考資料
[1]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
推薦閱讀
我的公眾號能帶來什么價值?(文末有送書規(guī)則,一定要看)
每個前端工程師都應該了解的圖片知識(長文建議收藏)
為什么現(xiàn)在面試總是面試造火箭?
