目的
Github上的类型体操,让你写出更加优雅的TS类型定义,以及探寻TS中我们不熟悉的只是,让我们开始TS的类型挑战把~2022希望通过更文的方式来督促自己学习,每日三题,坚持日更不断~~
题目大纲
01. Replace All
题目要求
import { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<ReplaceAll<'foobar', 'bar', 'foo'>, 'foofoo'>>,
Expect<Equal<ReplaceAll<'foobar', 'bag', 'foo'>, 'foobar'>>,
Expect<Equal<ReplaceAll<'foobarbar', 'bar', 'foo'>, 'foofoofoo'>>,
Expect<Equal<ReplaceAll<'t y p e s', ' ', ''>, 'types'>>,
Expect<Equal<ReplaceAll<'foobarbar', '', 'foo'>, 'foobarbar'>>,
Expect<Equal<ReplaceAll<'barfoo', 'bar', 'foo'>, 'foofoo'>>,
Expect<Equal<ReplaceAll<'foobarfoobar', 'ob', 'b'>, 'fobarfobar'>>,
Expect<Equal<ReplaceAll<'foboorfoboar', 'bo', 'b'>, 'foborfobar'>>,
Expect<Equal<ReplaceAll<'', '', ''>, ''>>,
]
我的答案
type ReplaceAll<
S extends string,
From extends string,
To extends string
> = From extends ""
? S
: S extends `${infer T}${From}${infer K}`
? `${T}${To}${ReplaceAll<K, From, To>}`
: S;
知识点
- 相较于Replace而言, 字符串模版推断支持 TS 递归,所以增加一层对后面子字符串在进行替换的递归操作即可
2. Medium Add Arguement
题目要求
import { Equal, Expect } from '@type-challenges/utils'
type Case1 = AppendArgument<(a: number, b: string) => number, boolean>
type Result1 = (a: number, b: string, x: boolean) => number
type Case2 = AppendArgument<() => void, undefined>
type Result2 = (x: undefined) => void
type cases = [
Expect<Equal<Case1, Result1>>,
Expect<Equal<Case2, Result2>>,
]
我的解答
type ARGS<T extends any> = T extends (...args: infer P) => any ? P : never;
type MyReturn<T extends any> = T extends (...args: any[]) => infer P
? P
: never;
type AppendArgument<Fn, A> = (
...args: [...ARGS<Fn>, ...[x: A]]
) => MyReturn<Fn>;
知识点
- 函数的参数的变更其实就是推断出函数的参数的数组的变化,所以直接推断出对应的函数参数的数组类型,进行追加即可
- 函数参数的追加可以通过
...扩展运算符来实现 - 定义参数类型就和函数定义参数类型的方式类似
3. Medium Permutation
题目要求
import { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<Permutation<'A'>, ['A']>>,
Expect<Equal<Permutation<'A' | 'B' | 'C'>, ['A', 'B', 'C'] | ['A', 'C', 'B'] | ['B', 'A', 'C'] | ['B', 'C', 'A'] | ['C', 'A', 'B'] | ['C', 'B', 'A']>>,
Expect<Equal<Permutation<'B' | 'A' | 'C'>, ['A', 'B', 'C'] | ['A', 'C', 'B'] | ['B', 'A', 'C'] | ['B', 'C', 'A'] | ['C', 'A', 'B'] | ['C', 'B', 'A']>>,
Expect<Equal<Permutation<never>, []>>,
]
我的解答
type Permutation<T extends any, U = T> = (() => T) extends () => never
? []
: T extends U
? [T, ...Permutation<Exclude<U, T>>]
: [];
知识点
- type 是"a" | "b" | "c"这种联合类型,目前需要将其处理成联合类型的自由组合, 如果想去掉一个类型,剩下两个自由组合的话可以参考下面的这个例子
type B = "A" | "B" | "C";
type EE<T, U = T> = T extends U ? [T, Exclude<U, T>] : never;
type ee = EE<B>;
// type ee = ["A", "B" | "C"] | ["B", "A" | "C"] | ["C", "A" | "B"]