这个函数实际上非常简单,它要么返回一个函数,要么返回一个字符串,具体取决于内部函数参数。
function strBuilder(str: string) {
return function next(str2?: string) {
if(typeof str2 === "string") {
return strBuilder(str + str2)
} else {
return str
}
}
}
但是执行此表达式时出现类型错误
strBuilder("Hello, ")("World")()
我想知道如何正确注释此函数,以便消除类型错误,因为推理效果不太好。
我想到了这种类型,但我找不到一种方法来告诉函数属于该特定类型。
type StringBuilder<S extends string> = (
str: S
) => (str2?: S) => S extends string ? ReturnType<StringBuilder<S>> : string
感谢任何形式的帮助。
这里最简单的方法可能是将
strBuilder()
的返回类型表示为 重载函数 类型:
interface StringBuilder {
(str: string): StringBuilder;
(): string;
}
function strBuilder(str: string): StringBuilder {
return function next(str2?: string) {
if (typeof str2 === "string") {
return strBuilder(str + str2)
} else {
return str
}
} as StringBuilder // <-- assert
}
我们需要一个断言,因为编译器无法准确验证函数实现是否符合重载调用签名(请参阅如何在 TypeScript 中正确重载函数?)。
无论如何,上面的代码都会编译并产生所需的调用行为:
const str = strBuilder("Hello, ")("World")();
console.log(str.toUpperCase())
您可以将其写为泛型条件类型,但这更复杂并且不一定更理想(这实际上取决于用例):
interface StringBuilder {
<S extends string | undefined = undefined>(str?: S):
S extends string ? StringBuilder : string;
}
ReturnType
并且不用担心在原始函数和返回函数内使用相同的 S
,这不是你想要的),当有人不带参数调用该函数时,我会给 S
一个 default(否则它会回落到
string | undefined
,这没有用)。
您仍然需要在
strBuilder()
的主体内进行类型断言,因为编译器也无法准确验证函数实现是否符合通用条件返回类型;请参阅 microsoft/TypeScript#33912。因此,就类型安全而言,您并没有获得或失去任何东西。
无论如何,它的行为与上面的示例相同:
const str = strBuilder("Hello, ")("World")();
console.log(str.toUpperCase())
我可能会坚持使用重载,除非你遇到一些特定的问题。