type X = {
x: {
a: 1
b: 'hi'
}
y: 'hey'
}
type Expected = {
readonly x: {
readonly a: 1
readonly b: 'hi'
}
readonly y: 'hey'
}
type Todo = DeepReadonly<X> // should be same as `Expected`
正确解答
type DeepReadonly<T extends Object> = {
readonly [Key in keyof T]: T[Key] extends Record<any, any>
? T[Key] extends Function
? T[Key]
: DeepReadonly<T[Key]>
: T[Key]
}
递归解决,注意特判 Funtion 的情况
10・元组转合集
实现泛型 TupleToUnion<T>,它返回元组所有值的合集。
例如
type Arr = ['1', '2', '3']
type Test = TupleToUnion<Arr> // expected to be '1' | '2' | '3'
解答: 没想太多的递归实现 👇
type TupleToUnion<T> = T extends [infer V, ...infer Rest] ? V | TupleToUnion<Rest> : never
type arr1 = ['a', 'b', 'c', 'd']
type arr2 = [3, 2, 1]
type re1 = Pop<arr1> // expected to be ['a', 'b', 'c']
type re2 = Pop<arr2> // expected to be [3, 2]
额外:同样,您也可以实现 Shift,Push和 Unshift吗?
正确解答:看了小册后不难做出
type Pop<T extends any[]> = T extends [...infer Rest, infer L] ? Rest : T
type Push<T extends any[], Arr extends any[]> = [...T, ...Arr]
type Shift<T extends any[]> = T extends [infer F, ...infer Rest] ? Rest : T
type Unshift<T extends any[], Arr extends any[]> = [...Arr, ...T]
type trimed = TrimLeft<' Hello World '> // 应推导出 'Hello World '
type Space = ' ' | '\n' | '\t'
type TrimLeft<S extends string> = S extends `${Space}${infer NewS}` ? TrimLeft<NewS> : S
108・Trim ⭐
实现Trim<T>,它是一个字符串类型,并返回一个新字符串,其中两端的空白符都已被删除。
例如
type trimed = Trim<' Hello World '> // expected to be 'Hello World'
正确解答:结合上一题,易得 TrimRight 的实现方法,二者结合即可实现 Trim
type Space = ' ' | '\n' | '\t'
type TrimLeft<S extends string> = S extends `${Space}${infer NewS}` ? TrimLeft<NewS> : S
type TrimRight<S extends string> = S extends `${infer NewS}${Space}` ? TrimLeft<NewS> : S
type Trim<S extends string> = TrimLeft<TrimRight<S>>
type Space = ' ' | '\n' | '\t'
type Trim<S extends string> = S extends `${Space}${infer NewS}` | `${infer NewS}${Space}` ? Trim<NewS> : S
110・Capitalize
实现 Capitalize<T> 它将字符串的第一个字母转换为大写,其余字母保持原样。
例如
type capitalized = Capitalize<'hello world'> // expected to be 'Hello world'
正确解答:还是通过模式匹配,使用内置类型 Uppercase 进行大写转换
type MyCapitalize<S extends string> = S extends `${infer F}${infer Rest}` ? `${Uppercase<F>}${Rest}` : S
116・Replace ⭐
实现 Replace<S, From, To> 将字符串 S 中的第一个子字符串 From 替换为 To 。
例如
type replaced = Replace<'types are fun!', 'fun', 'awesome'> // 期望是 'types are awesome!'
正确解答:注意 From 为空的情况
type Replace<S extends string, From extends string, To extends string> = S extends `${infer Pre}${From}${infer Post}`
? From extends ''
? S
: `${Pre}${To}${Post}`
: S
119・ReplaceAll ⭐⭐
实现 ReplaceAll<S, From, To> 将一个字符串 S 中的所有子字符串 From 替换为 To。
例如
type replaced = ReplaceAll<'t y p e s', ' ', ''> // 期望是 'types'
正确解答:在上题基础上,递归!
type ReplaceAll<S extends string, From extends string, To extends string> = S extends `${infer Pre}${From}${infer Post}`
? From extends ''
? S
: `${Pre}${To}${ReplaceAll<Post, From, To>}`
: S