在线编辑器:TypeScript Playground
13. Capitalize
大写第一个字母
type MyCapitalize<S extends string> = S extends `${infer First}${infer Rest}`
? `${Uppercase<First>}${Rest}`
: S;
type Test = MyCapitalize<'abc'>; // 'Abc'
14. Replace
实现可以替换的类型
type Replace<
S extends string,
From extends string,
To extends string,
> = From extends ''
? S
: S extends `${infer Prev}${From}${infer After}`
? `${Prev}${To}${After}`
: S;
type Test = Replace<'hello world', 'world', 'js'>; // hello js
本题没做出来。以往对字符串的想法有误,使用
extends对字符串进行解构,可以根据相应的模式自由解构。
15. ReplaceAll
type ReplaceAll<
S extends string,
From extends string,
To extends string
> = From extends ''
? S
: S extends `${infer Prev}${From}${infer After}`
? ReplaceAll<Replace<`${Prev}${To}${After}`, From, To>, From, To>
: S;
type Test = ReplaceAll<'$ $ $!', '$', 'js'>; // js js js!
循环 Replace 即可
16. AppendArgument
追加参数
type AppendArgument<
Fn extends (...args: any[]) => unknown,
Arg extends unknown
> = (...args: [...Parameters<Fn>, Arg]) => ReturnType<Fn>
type TestFun = AppendArgument<(a: string) => void, number>;
// (args_0: string, args_1: number) => void
生动地展示了为啥
Parameters<T>的结果为啥是数组
17. Length of String
type StringLength<S extends string, A extends string[] = []> =
S extends `${infer F}${infer R}` ? StringLength<R, [...A, F]> : A['length']
type Test = StringLength<'123'> // 3
字符串虽然有 length 属性,但是在类型里面直接 S['length'] 拿到的是 number,所以这里就简单将字符串转为数组了
18. Flatten
type Flatten<Arr extends any[]> = Arr extends [infer E, ...infer R]
? E extends any[]
? [...Flatten<E>, ...Flatten<R>]
: [E, ...Flatten<R>]
: Arr;
type Test = Flatten<[1, [2, [3, [4]]]]>; // [1, 2, 3, 4]
19. AppendToObject
追加属性
type AppendToObject<O extends {}, Key extends string, Value extends any> = {
[K in (keyof O | Key)]: K extends keyof O ? O[K] : Value;
}
type Test = AppendToObject<{ k: 1 }, 'k2', number>; // { k2: number; k: 1 }
也可以使用
&对两个进行合并,只是结果会展示为O & {...}感觉不够完美,所以将keyof O | Key进行遍历,这样结果就是一个完整的对象。
20. Absolute
返回取绝对值后的字符串
type Absolute<T extends string | number | bigint> = `${T}` extends `${infer F}${infer R}`
? F extends '-'
? R
: `${T}`
: `${T}`
type Test = Absolute<-123.123>; // '123.123'
21. StringToUnion
取每个字符转为 union type
type StringToUnion<S extends string> = S extends `${infer F}${infer R}`
? F | StringToUnion<R>
: S extends ''
? never
: S;
type Test = StringToUnion<'abc'>; // 'a' | 'b' | 'c'
22. Merge
合并对象属性,第二个覆盖第一个
type Merge<First extends {}, Second extends {}> = {
[K in (keyof First | keyof Second)]: K extends keyof Second
? Second[K]
: K extends keyof First
? First[K]
: never;
}
type Test = Merge<{ k1: 'k1', k: 'k' }, { k2: 'k2', k1: 'k2' }>;
// { k1: "k2"; k: "k"; k2: "k2" }
23. CamelCase
短横线转小驼峰
type CamelCase<S extends string> = S extends `${infer F}-${infer R}`
? `${F}${CamelCase<MyCapitalize<R>>}`
: S;
type Test = CamelCase<'foo-bar-baz'>; // fooBarBaz
24. KebabCase
驼峰转短横线
type KebabCase<S extends string, R extends string = ''> =
S extends `${infer F}${infer Rest}`
? F extends Uppercase<F>
? KebabCase<Rest, R extends '' ? Lowercase<F> : `${R}-${Lowercase<F>}`>
: KebabCase<Rest, R extends '' ? F : `${R}${F}`>
: R;
type Test = KebabCase<'FooBarBaz'>; // foo-bar-baz
25.Diff
对 O1 和 O2 进行 diff,取不同的 key 组成新对象
type DiffKey<O1 extends {}, O2 extends {}> =
Exclude<keyof O1, keyof O2> | Exclude<keyof O2, keyof O1>;
type Diff<O1 extends {}, O2 extends {}> = {
[K in DiffKey<O1, O2>]: K extends keyof O1
? O1[K]
: K extends keyof O2
? O2[K]
: never;
}
type Test = Diff<{ k: 1 , k1: 2 }, { k: 3, k2: 4 }>; // { k1: 2, k2: 4 }