这个(游乐场链接)不起作用:
type ReplaceAll2ndArgType = string | ((substring: string, ...args: unknown[]) => string)
export async function renderHTMLTemplate(
args: Record<string, ReplaceAll2ndArgType>
): Promise<string> {
let template = "some template text"
for (const key in args) {
const val = args[key]
template = template.replaceAll(`%${key}%`, val)
}
return template
}
打字稿编译器给出此错误:
No overload matches this call.
Overload 1 of 2, '(searchValue: string | RegExp, replaceValue: string): string', gave the following error.
Argument of type 'ReplaceAll2ndArgType' is not assignable to parameter of type 'string'.
Type '(substring: string, ...args: unknown[]) => string' is not assignable to type 'string'.
Overload 2 of 2, '(searchValue: string | RegExp, replacer: (substring: string, ...args: any[]) => string): string', gave the following error.
Argument of type 'ReplaceAll2ndArgType' is not assignable to parameter of type '(substring: string, ...args: any[]) => string'.
Type 'string' is not assignable to type '(substring: string, ...args: any[]) => string'.
问题似乎是打字稿无法弄清楚联合类型 ReplaceAll2ndArgType 由一组适合 template.replaceAll 可用原型集的类型组成,这似乎有点令人惊讶。 看起来它一次只考虑一个原型。 还是我没有正确理解问题?
到目前为止我唯一的解决方法看起来像这样(playground链接):
type ReplaceAll2ndArgType = string | ((substring: string, ...args: unknown[]) => string)
export async function renderHTMLTemplate(
args: Record<string, ReplaceAll2ndArgType>
): Promise<string> {
let template = "some template text"
for (const key in args) {
const val = args[key]
switch ( typeof val ) {
case "string":
template = template.replaceAll(`%${key}%`, val)
break
case "function":
template = template.replaceAll(`%${key}%`, val)
break
}
}
return template
}
这看起来真的很差,特别是因为
case "function"
并没有真正做太多有用的缩小。
我缺少什么更好的方法吗?
您遇到了 microsoft/TypeScript#44919 中报告的问题。
无论出于何种原因,replaceAll()
字符串方法
的TypeScript库类型被写成一对重载:
interface String {
replaceAll(
searchValue: string | RegExp,
replaceValue: string
): string;
replaceAll(
searchValue: string | RegExp,
replacer: (substring: string, ...args: any[]) => string
): string;
}
TypeScript 目前一次只能解析对重载一个调用签名的调用。您的呼叫必须至少匹配其中一个呼叫签名。但是您正在使用
union 类型的第二个参数来调用
replaceAll()
。该联合体的每个成员都与调用签名之一匹配,但联合体本身却不匹配。 除非按照 microsoft/TypeScript#14107 中的要求,TypeScript 支持一次调用多个调用签名,否则您需要以某种方式解决它。
一种解决方法如您在问题中所示:使用控制流来区分第二个参数的类型,以便调用可以匹配其中一个重载。
另一个解决方法是采用 microsoft/TypeScript#44919 中要求的方法,并使
replaceAll()
具有适当的调用签名。您无法摆脱现有的一对调用签名,但您可以为您自己的代码库合并第三个调用签名:
declare global {
interface String {
replaceAll(
searchValue: string | RegExp,
replacerOrValue: string | ((substring: string, ...args: any[]) => string)
): string;
}
}
我所做的就是手动组合两个调用签名。一旦您这样做,您的呼叫就会开始工作,因为它与新的呼叫签名匹配:
template = template.replaceAll(`%${key}%`, val) // okay