关于 typescript 中的 replace

ForkKillet
  • 1.3k
parse(): string {
    const syntax: [
        RegExp,
        string | ((s: string, ...g: string[]) => string)
    ] [] = [ 
        [ /^#! (\S+\/)+\n/m, (_, tags) =>
            tags.split("/").map(tag => tag 
                ? `<mark>${tag}</mark>` : ""
            ).join("")
        ],  
        [ /^(#{1,6}) (.+)$/mg, (_, sharps, text) => {
            const hx = "h" + sharps.length
            return `<${hx}>${text}</${hx}>`
        } ],
        [ /(?<!\\)((?:\\\\)*)`([^`\n]*?)(?<!\\)((?:\\\\)*)`/g, (_, __, text) =>
            `<code>${text}</code>`
        ],  
        [ / {2}\n/g, "<br />" ]
    ]   
    return syntax.reduce((t, p) => t.replace(p[0], p[1]), this.text)
}

就是很简单的从一个数组里拿参数塞给 replace
问题在于我 syntax 要么是 [ RegExp, string ][],要么是 [ RegExp, (...arg: string[]) => string ],只要我写成联合类型他就报错

No overload matches this call.                             
  The last overload gave the following error.
    Argument of type 'string | ((s: string, ...g: string[]) => string)' is     
not assignable to parameter of type '(substring: string, ...args: any[]) => string'.                                                                           Type 'string' is not assignable to type '(substring: string, ...args: any[]) => string'.  

求助

回复
阅读 160
1 个回答
✓ 已被采纳

String.prototype.replace 定义了几个重载,这里涉及到的是

  • replace(s: string | RegExp, r: string)
  • replace(s: string | RegExp, replacer: (substring: string, ...args: any[]) => string

很遗憾它并没有定义这样一个重载:

replace(
    s: string | RegExp,
    r: string | (substring: string, ...args: any[]) => string
)

所以直接给一个 string | (substring: string, ...args: any[]) => string 类型的值作为第二个参数是不行的,应该按情况区分开来

    return syntax.reduce((t, p) => {
        return typeof p[1] === "string"
            ? t.replace(p[0], p[1])  // 这里 p[1] 明确是 string
            : t.replace(p[0], p[1])  // 这里 p[1] 明确是 (...) => string
    }, this.text)

如果把参数从数组里拆出来,VSCode 里可以看到明确的类型提示:

image.png

实际上在写代码的时候,为了运行时少做一次判断,可以这样写

强制使用 any 来绕过类型检查,但是注释里要说清楚这样的原因
    // NOTE 明确 p[1] 是 String.prototype.replace 第 2 个参数可接受的类型,不存在例外
    return syntax.reduce((t, p) =>t.replace(p[0], p[1] as any), this.text)
你知道吗?

宣传栏