type-challenges:Replace

62 阅读1分钟

Replace

问题描述

实现 Replace<S, From, To> 将字符串 S 中的第一个子字符串 From 替换为 To

例如

type replaced = Replace<'types are fun!', 'fun', 'awesome'> // 期望是 'types are awesome!'
// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'type cases = [
  Expect<Equal<Replace<'foobar', 'bar', 'foo'>, 'foofoo'>>,
  Expect<Equal<Replace<'foobarbar', 'bar', 'foo'>, 'foofoobar'>>,
  Expect<Equal<Replace<'foobarbar', '', 'foo'>, 'foobarbar'>>,
  Expect<Equal<Replace<'foobarbar', 'bar', ''>, 'foobar'>>,
  Expect<Equal<Replace<'foobarbar', 'bra', 'foo'>, 'foobarbar'>>,
  Expect<Equal<Replace<'', '', ''>, ''>>
]
​
// ============= Your Code Here =============
// 答案1
type Replace<S extends string, From extends string, To extends string> =
  S extends `${infer L}${From extends ''
  ? never
  : From}${infer R}`
  ? `${L}${To}${R}`
  : S
// 答案2
type Replace<S extends string, From extends string, To extends string> =
  From extends ''
    ? S
    : S extends `${infer A}${From}${infer B}`
    ? `${A}${To}${B}`
    : S;
​
// 错误答案
type Replace<S extends string, From extends string, To extends string> =
  S extends `${infer L}${From extends ''
  ? ''
  : From}${infer R}`
  ? `${L}${To}${R}`
  : S
​

这道题第一次见可能很难想到这种方式,Replace接受三个参数:S(源字符串),From(要替换的子字符串)和To(用于替换的新子字符串)。类型操作符的目的是将字符串S中的所有From子字符串替换为To子字符串。

实现原理:

  1. 使用infer关键字定义两个类型变量LR,它们分别表示S的左侧和右侧部分。
  2. 使用extends关键字检查S是否以From结尾,如果是,则将其替换为To
  3. 如果S不是以From结尾,则保持原样。

可能有人好奇为什么 From extends ''? '': From 这样就不可以呢,因为这样就会导致中间的内容为空,泛型 L 和泛型 R 拼接到一起了。

或者也可以先排除空字符串的情况,参考答案2。