There seems to be an issue with this (playground link) code snippet:
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
}
Upon compiling in typescript, the following error is thrown:
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'.
It appears that typescript is struggling to understand that the union type ReplaceAll2ndArgType contains types that match the prototypes available for template.replaceAll function. This behavior seems unexpected as it evaluates the prototypes one by one. Is my understanding of the problem correct?
My current workaround involves modifying the code as shown in this (playground link):
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
}
This workaround seems ineffective, especially since the case "function"
doesn't provide much useful narrowing of the code. Is there a better solution that I might be overlooking?