TypeScript 为函数显式指定返回类型添加支持,

5jdjgkvh  于 9个月前  发布在  TypeScript
关注(0)|答案(6)|浏览(90)

搜索词

explicit infer return type

建议

infer 类型添加支持,该类型可用于明确表示函数的返回类型应从其实现中推断。对于函数(或箭头函数)具有显式的 infer 返回类型,其可观察行为与未指定返回类型相同:返回类型从实现中推断。
区别在于,现在技术上该函数确实有指定的返回类型,以指示开发人员明确决定允许返回类型被推断,而不是简单地忘记考虑返回类型应该是什么。

使用场景

在具有严格/显式代码风格的项目中,通常希望使用要求所有函数都有指定返回类型的linting规则(例如tslint的 "call-signature" typedef规则)。
然而,有些情况下,函数的返回类型是复杂类型(涉及泛型等),使得返回类型更自然地从方法的实现中推断出来,而不是提前知道预期的返回类型。
在这种情况下,如果能明确表示编译器推断函数的返回类型是有意义的,那将非常有益。这既能清楚地向其他阅读代码的开发人员传达这一明确意图,也可以用于满足要求函数具有指定返回类型的代码风格和linting规则。

为什么不能逐个禁用?

是的,可以使用tslint的行级规则禁用来临时禁用linting规则,让你在这种情况下省略返回类型。但我认为语言级别的显式 infer 返回类型支持会更有力、更清晰地表达意图。如果实现起来相对容易且风险较低,那就更加值得一试。
此外,没有足够的粒度来仅禁用 "typedef" 规则中的 "call-signature" 上下文。禁用该行上的 "typedef" 将同时禁用签名中的参数类型的检查,这是不希望看到的。

示例

一个简单的示例是单元测试中的辅助方法,使用 enzyme 。假设你有一个名为 MyButtonComponent 的自定义React组件,你想找到某个外部组件中的 "close" 按钮:

  1. import { ReactWrapper } from "enzyme";
  2. import { MyButtonComponent } from "./MyButtonComponent";
  3. function findCloseButton(wrapper: ReactWrapper): infer {
  4. return wrapper.find(MyButtonComponent).filter(".close-button");
  5. }

在这种情况下,上述 return wrapper.find(MyButtonComponent).filter(".close-button") 语句返回了一个严格类型的 ReactWrapper<P> 类型,其中 PMyButtonComponent 组件的 Props 类型,这允许通过 ReactWrapper 's props() 方法安全地访问组件当前属性值。
手动编写上述辅助函数的正确返回类型将相当繁琐,而且带来的好处非常有限。特别是如果 MyButtonComponent 的 Props接口无法轻易获得(因为它没有导出),或者因为 MyButtonComponent 是复杂泛型高级组件(HOC)创建的。在这种情况下,正确写出返回类型的努力远远超过了它的好处。

从隐式中推断

在以下示例中,没有实现可以从中推断返回类型的部分:

  1. declare function foo(a: number): infer;
  2. interface Bar {
  3. bar(b: string): infer;
  4. }

实际上, infer 类型在这里实际上是没有用的。也许只允许在存在可以推断的内容的情况下使用 any 类型会更有意义?如果是这样的话,那么上面的示例将是编译错误,因为没有任何东西可以推断。
另一个合理的选择可能是允许它以一种在 infer 编译器选项下会导致编译失败的方式推断隐式 any 类型。这种选项虽然不是最直接、最自然的选择,但完全可行且风险/努力最小。

部分推断类型

这是一个关于这个想法的扩展:

  1. function foo(value: number): Promise<infer> {
  2. // return value must be assignable to Promise<any>
  3. // return type is inferred to be Promise<number>
  4. return Promise.resolve(value);
  5. }
  6. interface Pair<A, B> {
  7. a: A;
  8. b: B
  9. }
  10. function bar(value: number): Pair<infer, infer> {
  11. // return value must be assignable to Pair<any, any>
  12. // return type is inferred to be Pair<number, boolean>
  13. return {
  14. a: value,
  15. b: value % 2 === 0
  16. };
  17. }

这将提供一个很好的结合点:在基本格式中验证你正在返回一些内容的同时让编译器推断复杂部分的类型,而这些复杂部分并不值得手动构造或编写。

待办事项清单

我的建议符合以下准则:

  • 这不会对现有的TypeScript/JavaScript代码造成破坏性改变
  • 这不会改变现有JavaScript代码的运行时行为
  • 这可以在不根据表达式的类型生成不同的JS代码的情况下实现
  • 这不是一个运行时特性(例如新的表达式级别语法)
c2e8gylq

c2e8gylq1#

What will we do when TSLint adds a rule that bans : infer ? 🤔

ljsrvy3e

ljsrvy3e2#

A TSLint规则禁止: infer对编译器支持: infer的决定不会产生影响,因为TSLint的用户可以选择启用/禁用哪些规则。这实际上提供了很好的灵活性。让我们想象一下添加了一个名为"no-infer-return-type"的新规则。您可以在函数签名上强制执行3级“严格性”:

  • 如果要在项目中允许隐式推断的返回类型,请禁用"call-signature"的"typedef"规则。
  • 如果要在项目中强制使用显式的非推断返回类型,请启用"call-signature"和"no-infer-return-type"的"typedef"规则。
  • 如果要在项目中强制使用显式返回类型,但仍然允许: infer,请启用"call-signature"和禁用"no-infer-return-type"的"typedef"规则。
vddsk6oq

vddsk6oq3#

你也可以明确表示你的意图使用推断出的返回类型,通过使用 // tslint:disable-next-line typedef ,然后不需要新的 TS 更改。

db2dz4w8

db2dz4w84#

是的,我已经确认了这一点。
是的,tslint支持行级规则禁用,可以用来临时禁用linting规则,让您在这种情况下省略返回类型。但我认为,对于显式推断返回类型的语言级支持会更加强大、清晰和表达力。如果实现起来相对容易且风险较低,那么就更有价值。
此外,没有足够的粒度来仅针对"call-signature"上下文禁用"typedef"规则。在该行上禁用"typedef"也将禁用签名中参数类型的检查,这是不希望看到的。
编辑:更新原始建议以澄清这一点

flmtquvp

flmtquvp5#

(编辑:将此添加到主要问题评论中)

对这个想法的扩展部分是推断返回类型:

  1. function foo(value: number): Promise<infer> {
  2. // return value must be assignable to Promise<any>
  3. // return type is inferred to be Promise<number>
  4. return Promise.resolve(value);
  5. }
  6. interface Pair<A, B> {
  7. a: A;
  8. b: B
  9. }
  10. function bar(value: number): Pair<infer, infer> {
  11. // return value must be assignable to Pair<any, any>
  12. // return type is inferred to be Pair<number, boolean>
  13. return {
  14. a: value,
  15. b: value % 2 === 0
  16. };
  17. }

这将提供一个很好的编译时验证,即您正在以基本格式返回您打算的内容,但让编译器推断出不值得手动构造/编写的复杂类型的部分。

展开查看全部
dzjeubhm

dzjeubhm6#

关于我之前的评论的一些后续想法...
我认为实现部分推断返回类型应该是相当容易的。基本概念是:

  • 如果 infer 存在于返回类型中的任何地方,那么推断函数的返回类型。
  • 验证推断出的返回类型是否可以分配给指定的返回类型:
  • 通过将指定返回类型中的所有 infer 替换为 any 来创建一个临时的 "expected" 返回类型。
  • 如果推断出的返回类型不能分配给临时的 "expected" 返回类型,则失败。

这种通用方法适用于完全和部分推断返回类型。

相关问题