该函数实际上非常简单,它根据内部函数参数返回函数或字符串.

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/C4TwDgpgBAysBOBLAdgcwEIFdEBsAmE8APDFBAB7ATJ4DOUtCKqAfFALxQAUAUFAwgBcsHgEoObLo3gAmAPzCY49m1IUqNetOZQ5UAEoRgmeMgAq4CCSZosuAsRgs2w7Wh48AZpmQBjYIgA9sgC8Hb4hFJCocziAN58UPBGJiHefgHBUMjqUbIKMWjxifyInlygkIGeoTIc7JwARG6ojcX8HUkppqHhDnlQANS1oiVQAL5kOLTQCZ38ycY90mPjiWtrPNJ9kY0AEhA4OIEANFBtXI0A6oHw+BejQA的操场链接

推荐答案

这里最简单的方法可能是将strBuilder()的返回类型表示为overloaded function类型:

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
}

我们需要assertion,因为编译器不能准确地验证函数实现是否符合重载的调用签名(参见How to correctly overload functions in TypeScript?).

无论如何,上述代码都会编译并产生所需的调用行为:

const str = strBuilder("Hello, ")("World")();
console.log(str.toUpperCase())

could将其编写为generic conditional type,但这更复杂,也不一定更可取(这真的取决于用例):

interface StringBuilder {
  <S extends string | undefined = undefined>(str?: S):
     S extends string ? StringBuilder : string;
}

这与您的版本类似,只是我只是直接表示返回类型(这样就不会使用ReturnType,这样就不必担心在原始函数和返回函数内使用相同的S,这不是您想要的),如果有人在没有参数的情况下调用函数,我给出的值是defaultS(否则它将回退到string | undefined,这是没有用的).

strBuilder()的主体中仍然需要类型断言,因为编译器也无法准确验证函数实现是否符合泛型条件返回类型;请参见microsoft/TypeScript#33912.因此,在类型安全方面,您不会得到或失go 任何东西.

无论如何,对于上面的示例,它的行为是相同的:

const str = strBuilder("Hello, ")("World")();
console.log(str.toUpperCase())

我可能会坚持使用重载,除非您遇到一些具体的麻烦.

Playground link to code

Typescript相关问答推荐

类型脚本不会推断键的值类型

TypScript ' NoInfer '类型未按预期工作

如何使用泛型类型访问对象

在配置对象上映射时,类型脚本不正确地推断函数参数

如何将类型从变量参数转换为返回中的不同形状?

类型脚本类型字段组合

未在DIST中正确编译TypeScrip src模块导入

在分配给类型的只读变量中维护const的类型

Angular:ngx-echart 5.2.2与Angular 9集成错误:NG 8002:无法绑定到选项,因为它不是div的已知属性'

剧作家元素发现,但继续显示为隐藏

NPM使用Vite Reaction应用程序运行预览有效,但我无法将其部署到Netlify

如何键入派生类的实例方法,以便它调用另一个实例方法?

打印脚本中正则函数和函数表达式的不同类型缩小行为

如何使函数参数数组不相交?

任何导航器都未处理有效负载为";params";:{";roomId";:";...";}}的导航操作

通过函数传递确切的类型,但验证额外的字段

什么';是并类型A|B的点,其中B是A的子类?

Karma Angular Unit测试如何创建未解析的promise并在单个测试中解决它,以判断当时的代码是否只在解决后运行

React-Router V6 中的递归好友路由

TS 条件类型无法识别条件参数