Tslint: 'no-inferrable-types' 和 'typedef' 规则冲突

创建于 2015-10-03  ·  33评论  ·  资料来源: palantir/tslint

你好,我们又见面了,

我不确定这是问题还是设计决定,但我可以看到规则no-inferrebale-typestypedef之间的冲突。

前任。

function fn(): void {
    for (let i = 0; i < 100; i++) {
        console.log(i);
    }
}

来自https://github.com/palantir/tslint/blob/master/docs/sample.tslint.json的片段:

 "typedef": [true, ...],
 "no-inferrable-types": true,

当我打开这两个规则时,我得到:

error (typedef) test.ts[2, 12]: expected variable-declaration: 'i' to have a typedef

将类型注释number添加到变量i会依次导致以下错误:

error (no-inferrable-types) test.ts[2, 14]: LHS type (number) inferred by RHS expression, remove type annotation

有没有办法让这两个规则共存?

例如,我想用原始类型直接声明可推断变量(如规则文档所说: numberbooleanstring ),但另一方面,我想要在非原始类型上强制使用 typedef。

谢谢,

O。

P1 Enhancement 🌹 R.I.P. 🌹

最有用的评论

:+1: 理想情况下(imo)我想说“总是需要 typedef,除非类型是可推断的”。 我认为现在不可能。

所有33条评论

很好的收获,感谢您的提醒。 我添加了no-inferrable-types规则,没有考虑它可能与typedef规则冲突,哎呀! 现在我建议关闭两者之一,或者只使用typedef规则的一些选项。

从长远来看,我认为我们要么希望将no-inferrable-types集成到typedef规则中,要么我们希望至少让 TSLint 检测冲突配置,例如同时启用这两个规则。

我面临同样的问题。
我现在已经关闭了 no-inferrable-types。

是的,这里也一样,我希望有能力让这两个规则共存。
如果可以推断出变量的类型,我不希望 typedef 规则生效。
即“no-inferrable-types”应该优先于“typedef”

+1

let id: number = 0;
for (let job: string of NAMES_PROFFESSIONS) {
     /** some code */
     id++;
}

(no-inferrable-types) LHS 类型(数字)由 RHS 表达式推断,去掉类型注释

+1

您对“可推断”类型的定义是否包括构造函数赋值?

// BAD (this hurts my eyes to read)
let labels: Map<string, string> = new Map<string, string>();
// GOOD (type is obvious)
let labels = new Map<string, string>();

但是也...

// BAD (in a diff, it's not obvious what this type is)
let labels = this.buildLabels();
// GOOD
let labels: Map<string, string> = this.buildLabels();

是的,这很危险。 如果我想简化我的代码并防止对直接初始化的变量使用类型声明,我不能严格这样做,这会带来这样的事情:

let x = 2;
let y;
let z: number;

x = 1;
y = 1;
z = 1;
x = 's'; // Type 'string' is not assignable to type 'number'
y = 's'; // It's OK
z = 's'; // Type 'string' is not assignable to type 'number'

仅允许对初始化变量进行跳过类型声明可能是一个非常有用的选项。

... 正如@pgonzal所说,实际上不仅适用于原始类型!
看看这个,太可怕了:

const onChange: () => void = () => this.update();

:+1: 理想情况下(imo)我想说“总是需要 typedef,除非类型是可推断的”。 我认为现在不可能。

我遇到了这个问题并制作了一个ignore-params标志,这对我的情况有所帮助。 我想对所有方法/函数参数强制使用 typedef,即使它们可以很容易地推断出来。

如果您想尝试一下,请参阅 PR:#1190

自从提交原始问题以来已经有一段时间了。 此时推荐选项是否禁用no-inferrable-types并在所有内容中包含类型? 尝试启用和组合no-inferrable-typestypedef的任何其他操作似乎都是一种 hack,并导致一堆毫无意义的警告。 希望在不久的将来有更好的解决方案。

@corydeppen请注意上面对@englercj建议的 8 个竖起大拇指。 目前尚不清楚您的“似乎是黑客”评论中的“组合”是什么意思。 如果您的意思是“在tslint.json中一起使用,那么,是的。但是在typedef上“组合”一个optional-inferrable-types参数会很棒(至少,对于我们中的 9 个人来说)。

请问我们可以得到这方面的更新吗?

我认为处理此问题的最佳方法是弃用no-inferrable-types并将选项对象传递给typedef以忽略类型定义的缺乏,如果根据某些模式可以推断类型,如initializedinitialized primitivescall signatures和其他可以满足我们开发人员需求的模式。

对我来说,这更有意义,因为应该总是有一个 typedef,除非有东西告诉你它是函数的类型。 而且它也是可配置的,因为,也许我们希望类中初始化的properties具有可推断的类型,但对于call signatures来说却不是这样。

如果有人能帮忙解决这个问题,那就太好了。 在那之前,我们被迫在“没有足够的类型声明可读”和“杂乱无章的类型声明”之间做出选择。

这个问题自 2015 年 10 月 3 日以来一直开放——从那时起,我的团队已经编写了大约 2000 个 TypeScript 源文件,这些文件都包含太多的类型声明。

typedef接受配置。 因此,如果类型是可推断的,则可能只是另一种配置来忽略类型定义,这意味着

只需在未初始化的地方键入。

看起来是因为在如何处理这个问题上没有明确的共识,所以没有取得任何进展。 示例评论: https ://github.com/theia-ide/theia/issues/356#issuecomment -319350833

我怀疑我们都同意任何解决方案都比保持现状更好。 如果您认为在这个问题上对现状的任何改变都是好的,请👍这个评论。 如果您有足够的知识创建 PR 来解决此问题,请帮助我们所有人❤️。

将接受 PR 以:

  • typedef添加一个选项,让它忽略no-inferrable-types表示不提供类型的情况

typedef 接受一个配置。 因此,如果类型是可推断的,则可能只是另一种配置,只是忽略类型定义,这意味着“只需在未初始化的地方键入即可。”

typedef规则适用于喜欢在代码库中明确类型定义的人。 如果您希望上述行为“只在未初始化的地方键入”,则最好禁用typedef并确保将noImplictAny启用为 TypeScript 编译器选项。

还有一个棘手的情况是,一些初始化的东西无论如何都需要 typedef,如下面的代码片段所示:

interface Literal {
    field: "value"
}

const literal0 = {
    field: "value",
};
const literal1: Literal = {
    field: "value",
};

const func = (obj: Literal) => { };
func(literal0);  // Error! Type 'string' is not assignable to type '"value"'.
func(literal1);

此外,虽然我们解决了这个问题,但想提一下,可能有一些很棒的第 3 方规则,比如no-unnecessary-type-annotation (https://github.com/ajafff​​/tslint-consistent-codestyle/blob/ master/docs/no-unnecessary-type-annotation.md)例如。 如果有人知道提供所需行为的任​​何其他 3rd 方规则,请在此处发布它们,我们可以正式推荐它们或在有意义的情况下将它们纳入核心。

@JKillian感谢您的推荐,我认为这实际上就是我想要的。 有一篇关于避免any类型的非常好的帖子:不要使用“naked any”,而是创建一个“any interface”。

关于:

interface Literal {
    field: "value"
}

const literal0 = {
    field: "value",
};
const literal1: Literal = {
    field: "value",
};

const func = (obj: Literal) => { };
func(literal0);  // Error! Type 'string' is not assignable to type '"value"'.
func(literal1);

我不明白这怎么可能是不受欢迎的行为,也不是一个棘手的案例。 您要确保obj $ 具有价值value的属性field $ ,即使您使用看起来像约束的属性初始化literal0 ,您可以将其修改为另一个字符串。

我知道这不是一个好的用例,但大多数情况下,当您使用文字时,您可能需要该文字,而不是原语。

我有以下配置:
json "no-inferrable-types": true, "typedef": [true, "call-signature", "parameter"],
而这段代码:
javascript private static readonly DEVICE_UID: string = 'device_uid'; private static readonly DEVICE_PLATFORM: string = 'browser'; private static readonly AGENT_DEFAULT_ICON = 'http://localhost:3000/icon.png';

为什么我在前两个声明中没有出错?

@sandrocsimas 很有趣,但我认为离题了; AFAICT,该问题与此问题无关。 我建议你开始另一个问题(fwiw!)。

@estaub ,是的,我会的。 即使没有 typedef 规则,我也会得到相同的行为。

@sandrocsimas那是因为它是一个只读属性,并且这样的 Typescript 将其类型推断为文字。 将其键入为字符串,您告诉它应该有一个字符串,它不一定具有该文字值,并且该值不应静态更改。

有一个“require-typedef-except-inferrable”规则会很好。

@FiretronP75正如@JKillian所说,这只是 TSC 的noImplicitAny选项。

@michaeljota谢谢,我没有意识到编译器的noImplicitAny选项提供了可推断的异常。 尽管如此,在 tslint 中仍然会很好,因为可以选择将其作为警告而不是破坏编译,并且可以使用 tslint 注释标志。

我明白为什么需要这样做,但是以no-unused-variables为例,我认为 TSC 涵盖的用例不会得到 TSLint 团队的支持。 我知道_linter error_ 与_compiler error_ 不同,但最后,它们都是关于编写更好的代码。 现在有了 Webpack 或 Parcel 等解决方案,即使出现 TSC 错误,您也可以编译和运行代码,我不认为这是一个真正的问题。

这个问题在最新版本中修复了吗?

我仍然认为这不在路线图上。 您应该考虑使用来自 TSC 的noImplicitAny

☠️ TSLint 的时间到了! ☠️

TSLint 不再接受每个 #4534 的大多数功能请求。 请参阅typescript-eslint.io了解使用ESLint对 TypeScript 代码进行 lint 的新方法。 ✨

很高兴与大家一起开源!

🤖哔哔! 👉 TSLint 已弃用👈 _(#4534)_ 你应该切换到typescript-eslint ! 🤖

🔒 此问题已被锁定,以防止进一步不必要的讨论。 谢谢! 👋

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

avanderhoorn picture avanderhoorn  ·  3评论

cateyes99 picture cateyes99  ·  3评论

denkomanceski picture denkomanceski  ·  3评论

mrand01 picture mrand01  ·  3评论

Ne-Ne picture Ne-Ne  ·  3评论