歷史小劇場
這個世界上,有兩種人最痛苦,第一種是身居高位者,第二種是身居底層者,第一種人很少,第二種人很多。第一種人叫崇禎,第二種人叫百姓。
而最幸福的,就是中間那撥人,主要工作,叫做欺上瞞下,具體特點是,除了好事,什么都辦;除了臉,什么都要。—《明朝那些事兒》
字符串模板與extends/infer
- extends: 有兩個作用:1、接口繼承,2、類型判斷(這篇文章主要是體現這個作用);
- infer: 推導泛型參數,只在extends右邊使用
案例
type str = "beyond";// 獲開頭
type getFirst<T> = T extends `${infer First}${infer Rest}`? First : never;
type FirstLetter = getFirst<str>; // type FirstLetter = "b"// 獲取除開頭的部分
type getRest<T> = T extends `${infer First}${infer Rest}` ? Rest : never;
type RestLetters = getRest<str>; // type RestLetters = "eyond"// 以y分隔
type Split<T> = T extends `${infer Front}y${infer Back}` ? Back : never;
type Splitted = Split<str>; // type Splitted = "ond"
判斷開頭
type startsWidth<str extends string, prefix extends string> = str extends `${prefix}${infer Rest}` ? true : false;
type startsWidthKong = startsWidth<"kong", "">; // type startsWidthKong = true
type StartsWithBe = startsWidth<str, "be">; //type StartsWithBe = true
type StartsWithC = startsWidth<str, "c">; // type StartsWithC = false
轉為首字母大寫
type UppercaseFirst<T extends string> = T extends `${infer First}${infer Rest}` ? `${Uppercase<First>}${Rest}` : never;
type UppercaseStr = UppercaseFirst<str>; // type UppercaseStr = "Beyond"
文本替換-替換第一個
type ReplaceOne<str extends string, from extends string, to extends string> = str extends `${infer Front}${from}${infer Rest}` ? `${Front}${to}${Rest}` : str;
type ReplaceStr = ReplaceOne<str, "o", "a">; // type ReplaceStr = "beyand"
鍵值對轉索引 a=1 => {a:1}
type ConvertStrToRecord<str extends string> = str extends `${infer key}=${infer value}` ? { [k in key]: value } : never;
type ConvertStrToRecordStr = ConvertStrToRecord<"a=1">;
// type ConvertStrToIndexStr = {// a: "1";
// }
as 重映射-索引的重命名
索引轉大寫
interface IOut {aaa: 1,bbb: 2,fun: () => void
}
type UpperKeys<T extends Record<string, any>> = {[K in keyof T as (T[K] extends Function ? K : Uppercase<K>)]: T[K]
}
type res = UpperKeys<IOut>;
// type res = {
// AAA: 1;
// BBB: 2;
// fun: () => void;
// }
合并索引
interface IOut2 {ccc: 3,ddd: 4
}
type CombineIndex<A extends Record<string, any>, B extends Record<string, any>> = {[K in keyof A | keyof B] : K extends keyof A ? A[K] : K extends keyof B ? B[K] : never
}
type combine = CombineIndex<IOut, IOut2>;
// type combine = {
// aaa: 1;
// bbb: 2;
// fun: () => void;
// ccc: 3;
// ddd: 4;
// }
巧用遞歸
文本替換-替換所有
type ReplaceAll<Str extends string, From extends string, To extends string> = Str extends `${infer Front}${From}${infer Rest}` ? `${Front}${To}${ReplaceAll<Rest, From, To>}` : Str;
type ReplaceAllStr = ReplaceAll<"12333333456", "3", "A">; // type ReplaceAllStr = "12AAAAAA456"
字符串反轉
type Reverse<Str extends string, Res extends string = ""> = Str extends `${infer First}${infer Rest}` ? Reverse<Rest, `${First}${Res}`> : Res;
type ReverseStr = Reverse<"hello">; // type ReverseStr = "olleh"
綜合
字符串解析-初級
例如:我們要將 a=1&b=2&c=3 轉為 {a:1, b:2, c:3}
那么,我們要有按這三步走
- &分割取 鍵值對 處理
- 處理單個的 鍵值對 轉換為 索引類型
- 把 轉換后的 索引類型 合并
type Parse<Str extends string, Res extends Record<string, any> = {}> = Str extends `${infer One}&${infer Rest}` ?Parse<Rest, CombineIndex<Res, ConvertStrToRecord<One>>> :CombineIndex<Res, ConvertStrToRecord<Str>>type parseToRecord = Parse<"a=1&b=2&c=3">; // type parseToRecord = {a: "1", b: "2", c: "3"}
字符串解析-升級
- 如果只有鍵沒有值,則返回 {key: true};
- 合并重復索引。例如 a=1&a=2 轉為 {a: [‘1’, ‘2’]};
- 合并的值不能重復。例如 a=1&a=2&a=2 轉為 {a: [‘1’, ‘2’]};
type ConvertStrToRecordUp<Str extends string> = Str extends `${infer Key}=${infer Value}` ? { [K in Key] : Value } : Str extends `${infer Key}` ? { [K in Key]: true } : {};
type ConvertStrToRecordUpStr = ConvertStrToRecordUp<"a">;
// type ConvertStrToRecordUpStr = {
// a: true;
// }// 合并重復索引
type CheckDuplicate<A extends Record<string, any>, B extends Record<string, any>> = keyof B extends keyof A ? AddR<A, B> : CombineIndex<A, B>;
type AddR<A extends Record<string, any>, B extends Record<string, any>> = {[K in keyof A] : K extends keyof B ?CheckInclue<A[K], B[K]> extends true ? A[K] : // 重復索引,合并值,值不能重復A[K] extends any[] ? [...A[K], B[K]] : [A[K], B[K]] : A[K]
}type CheckInclue<A extends any[], B extends string> = A extends [infer First, ...infer Rest] ? First extends B ? true : CheckInclue<Rest, B> : false;
type checkIncludeDemo = CheckInclue<["a", "b", "c"], "a">; // type checkIncludeDemo = truetype ParseUp<Str extends string, Res extends Record<string, any> = {}> = Str extends `${infer One}&${infer Rest}` ?ParseUp<Rest, CheckDuplicate<Res, ConvertStrToRecordUp<One>>> :CheckDuplicate<Res, ConvertStrToRecordUp<Str>>type parseToRecordUp = ParseUp<"a=1&b&a=2&a=3&c&d=4&e&e=10&a=3">;
// type parseToRecordUp = {
// b: true;
// c: true;
// a: ["1", "2", "3"];
// e: [true, "10"];
// d: "4";
// }