类型体操刷题系列(九)—Replace All/Add Arguement/Permutation

230 阅读2分钟

目的

Github上的类型体操,让你写出更加优雅的TS类型定义,以及探寻TS中我们不熟悉的只是,让我们开始TS的类型挑战把~2022希望通过更文的方式来督促自己学习,每日三题,坚持日更不断~~

ts 类型体操 github 我的解答

题目大纲

  1. Medium Replace All
  2. Medium Add Arguement
  3. Medium Permutation

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;

知识点

  1. 相较于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>;

知识点

  1. 函数的参数的变更其实就是推断出函数的参数的数组的变化,所以直接推断出对应的函数参数的数组类型,进行追加即可
  2. 函数参数的追加可以通过...扩展运算符来实现
  3. 定义参数类型就和函数定义参数类型的方式类似

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>>]
  : [];

知识点

  1. 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"]