TypeScript `noImplicitReturnType [建议]`

7y4bm7vi  于 4个月前  发布在  TypeScript
关注(0)|答案(8)|浏览(117)

我们有 noImplicitReturns,这很好,可以帮助纠正一些愚蠢的错误,但如果也能有 noImplicitReturnType 就好了。

那么 noImplicitReturnType 会做什么?

目前我们可以编写一个这样的函数:

function life () {
    return 42;
}
let x = life(); // Number

所以一切都很好,TypeScript 为我们很好地计算出了返回类型。

function life (x: boolean) {
    if (x) {
        return 'hi';
    } else {
        return 42;
    }
}
let y = life(true); // Number / String

这就是事情开始变得有点疯狂的地方。TypeScript 将 y 记录为类型 number | string,当然这是准确的。但是如果我想要这个函数只返回字符串呢?
我们已经有了对字符串的支持,只需做一些有限的修改即可

function life (x: boolean): string {
    if (x) {
        return 'hi';
    } else {
        return 42; // Type '42' is not assignable to type 'string'.
    }
}
let y = life(true);

结果,TypeScript 优雅地抛出了一个错误。
因此我的建议是,与 noImplicitAnylet 强制执行严格的类型检查一样,以 noImplicitReturnType 的形式添加一个参数,对于我的第一个例子(只有一个返回值),这不会有任何影响,但对于第二个,它将抛出一个错误,而不是将函数类型定义为 number | string

bwntbbo3

bwntbbo31#

你可能对typedef tslint规则感兴趣。

sauutmhj

sauutmhj2#

有趣的是,现在会设置这个,但我相信类似的东西应该在TS本身就有。

rggaifut

rggaifut3#

我担心新的开发者在完全理解TypeScript类型系统的本质和表达力之前就会启用这个功能。
更具体地说,我认为采用这个特性很可能会导致以下结果:

  1. 增加对any的使用
  2. 无法理解和利用联合类型和交叉类型
  3. 减少了CFA的好处
  4. 减少了泛型的使用
  5. 普遍的困惑
    关于TypeScript已经存在许多误解,导致不良的编码实践,无法充分利用该语言。
    这里有一个不幸的典型例子来自Stack Overflow问题:
export class ListComponent {
  items: any[] = [{id: 1, value: 'item1'}, {id: 2, value: 'item2'}, {id: 3, value: 'item3'}];
  myModel: any = {id: this.items[1].id , value: this.items[1].value};
}

我们都同意这样的代码是糟糕的,但为什么是这样写的呢?
我真的想强调上述模式是常见的。
我认为添加这个功能是一个严重的错误。

z18hc3ub

z18hc3ub4#

另一个更相关的例子是代码,如

function f(n: number) {
  return n % 2 === 0 ? 'even' : 'odd';
}

在使用建议的功能时,这将导致一个错误
错误:未指定返回类型。
当回应这个错误时,用户有多大可能写
function f(n: number): 'even' | 'odd' ?

hxzsmxv2

hxzsmxv25#

假设来自同一原始家族的单元类型的联合不会触发此错误。我对此表示同情,因为很容易做类似的事情

function fn() {
  if (x) return g();
  // ...
  return g;
}

然后在程序的其他地方处理一个难以理解的关于 foo | () => foo 的错误信息。我主张不要为函数返回类型创建联合类型,但承认在实践中它并没有那么大的问题。

u59ebvdq

u59ebvdq6#

@RyanCavanaugh 我完全理解想要在某些情况下添加错误标志的合理性,但与此同时,foo | () => foo 在某些情况下是非常有用且完全有效的类型。
我的担忧是,过早地使用这个标志可能会导致问题,如果它在一个TypeScript代码库中被启用,那么可能永远不会有人意识到他们甚至可以表达这样的类型。
此外,我想知道这个标志将如何分类。它会归属于--strict吗?这对我来说感觉不太对。

rkue9o1l

rkue9o1l7#

我也希望在TypeScript本身中出现这样的行为。
原因在于,函数的返回类型是其契约,通过修改函数可以轻易地破坏它。当然,在某些其他代码直接使用此类函数的情况下,TypeScript会发出警告,但并非所有以类型安全方式消耗的代码都应该提供稳定契约。
以服务器端控制器为例,其返回类型是客户端将接收到的内容,但控制器的方法是在某个第三方库中调用的,该库并不太关心它得到的函数结果是什么。

@Controller('foo')
export class FooController {
  @Get()
  bar() {
    return 5;
  }

  @Get()
  bar2(id: string) {  // <-- there should be error with proposed feature
    if (id === "secret") {
      return "some text";
    }
    return 0;
  }
}

因此,通常建议的编译器标志应在函数返回非 single 类型时抛出错误,以便开发人员可以审查更改并决定是破坏契约还是修复代码。
此外,建议的标志名称与其期望的行为不一致,如果 single 是推断出的类型,开发人员不应显式指定返回类型。

7xzttuei

7xzttuei8#

@salterok,这基本上就是我所寻找的,如果一个函数只返回一个 number 类型,那么它的类型应该被视为 number 类型,而不会有任何问题。只有自动联合类型会被阻止。

基本上,它可以像 noImplicitAny 对于 let x = y; 所做的那样,但是针对函数。或许一个更好的名称应该是类似于 noImplicitReturnUnion?

相关问题