Typescript 循环函数参考

问题描述 投票:0回答:1

这个函数实际上非常简单,它要么返回一个函数,要么返回一个字符串,具体取决于内部函数参数。

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

感谢任何形式的帮助。

这是演示该问题的游乐场链接https://www.typescriptlang.org/play?#code/C4TwDgpgBAysBOBLAdgcwEIFdEBsAmE8APDFBAB7ATJ4DOUtCKqAfFALxQAUAUFAwgBcsHgEoObLo3gAmAPzCY49m1IUqNetOZQ5UAEoRgmeMgAq4CCSZos UASRgs2w7Wh48AZpmQBjYIGA9sgC8Hb4hFJCocziAN58UPBGJiHefgHBUMjqUbIKMWjxifyInlygkIGeoTIc7JwARG6ojcX8HUkppqHhDnlQANS1oiVQAL5kOLTQCZ38ycY90mPjiWtrPNJ9ky0AEha4OIEANFBt XI0A6oHw+BejQA

typescript recursion functional-programming
1个回答
1
投票

这里最简单的方法可能是将

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())

我可能会坚持使用重载,除非你遇到一些特定的问题。

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.