TypeScript的严格模式实际上如何修复TypeScript

Strict mode is actually a combination of six other flags (as of TypeScript 3.8):

严格模式实际上是六个其他标志的组合(自TypeScript 3.8起):

  • noImplicitAny

    noImplicitAny

  • strictNullChecks (since 2.0)

    strictNullChecks (自2.0起)

  • noImplicitThis (since 2.0)

    noImplicitThis (自2.0开始)

  • strictFunctionTypes (since 2.6)

    strictFunctionTypes (自2.6起)

  • strictPropertyInitialization (since 2.7)

    strictPropertyInitialization (自2.7版开始)

  • strictBindCallApply (since 3.2)

    strictBindCallApply (从3.2开始)

Each option can be enabled or disabled separately. Some of them make TypeScript’s type checking better and some help make your code more readable and less error-prone.

可以分别启用或禁用每个选项。 它们中的一些使TypeScript的类型检查更好,而一些帮助使您的代码更具可读性,并且不易出错。

You can enable strict mode in your tsconfig.json:

您可以在tsconfig.json启用严格模式:

You can disable any option that you don’t like from the strict family in the compileOptions as well (e.g. "noImplicitAny": false).

您也可以在compileOptions禁用严格系列中您不喜欢的任何选项(例如"noImplicitAny": false )。

I think the most important flags are noImplicitAny and strictNullChecks. These two will really improve the type checking and readability of your code.

我认为最重要的标志是noImplicitAnystrictNullChecks 。 这两个将真正提高代码的类型检查和可读性。

Let’s take a look at each flag.

让我们看一下每个标志。

无隐含 (noImplicitAny)

Without turning noImplicitAny on, you are only mostly using TypeScript because now you have parts of your code that are of type any without you even noticing.

头也不回noImplicitAny上,你只大多采用打字稿,因为现在你有一个是类型的代码的部分any没有你甚至没有注意到。

Because the type any basically disables type check, you really shouldn’t have it unless you don’t have a choice. The problem is that it’s really easy to have any in your code by mistake, so by using noImplicitAny, you will now only have any where you explicitly use it.

因为any类型any基本上禁用了类型检查,所以除非没有选择,否则您实际上不应该使用它。 问题在于,错误地在代码中包含any非常容易,因此,通过使用noImplicitAny ,您现在将仅拥有any在显式使用它的位置。

Let’s see how easy it is to disable type checking by mistake:

让我们看看错误地禁用类型检查有多么容易:

In this example, we define a function (fn) that just returns what it gets. What we can easily miss is that the return type of this function is actually any.You can see that copyOfNum, which is just the same number as num, is now of type any and we can do all sorts of wrong things with it.

在此示例中,我们定义了一个函数( fn ),该函数仅返回其获取的内容。 我们很容易错过的是,该函数的返回类型实际上是any 。您可以看到与num相同的数字copyOfNum现在是any类型,我们可以用它做各种错误的事情。

If we turn noImplicitAny on, we won’t be able to define a function like fn that returns any implicitly and would have to define it correctly instead, resulting in copyOfNum not losing its type:

如果打开noImplicitAny ,我们将无法定义像fn这样的函数,该函数隐式返回any ,而必须正确定义它,从而导致copyOfNum不会丢失其类型:

Another common way we put any in our code without noticing is when importing an external module:

我们不加注意地将any代码放入代码中的另一种常见方式是在导入外部模块时:

Here, we just wanted to add 1 + 1 using lodash but got a result of type any because we didn’t have the types of lodash installed. This can be solved by installing @types/lodash. In case we are using an external module with no available types, we can write them ourselves using declare module ‘lodash’ { /* types goes here */}.

在这里,我们只想使用lodash加1 + 1,但是得到了any类型的结果,因为我们没有安装lodash类型。 这可以通过安装@types/lodash来解决。 如果我们使用的外部模块没有可用的类型,则可以使用declare module 'lodash' { /* types goes here */}自己编写。

If we are OK with this module being of type any or do not have the capacity right now to fix it, we can signal it to the compiler by declaring the module with no types:

如果我们对这个模块是any类型的模块没问题,或者现在没有修复它的能力,我们可以通过声明没有类型的模块来向编译器发出信号:

declare module ‘lodash’;

strictNullChecks (strictNullChecks)

The most common JS runtime error is probably Uncaught TypeError: Cannot read property ‘foo’ of undefined. This is caused when trying to access a property or call a method on an undefined object.

JS最常见的运行时错误可能是Uncaught TypeError: Cannot read property 'foo' of undefined. 这是在尝试访问undefined对象的属性或调用方法时引起的。

Luckily, TypeScript can help.

幸运的是,TypeScript可以提供帮助。

By default, null and undefined are assignable to all other types, while your code actually has many types that can never be null or undefined, making their types wrong by default.

默认情况下, nullundefined可以分配给所有其他类型,而您的代码实际上具有许多永远不能为nullundefined的类型,默认情况下会使它们的类型错误。

After enabling strictNullChecks, the only types that can be null or undefined are the ones explicitly marked as so. This means you wouldn’t be able to initialize a variable without a value. For example:

启用strictNullChecks ,唯一可以为nullundefined类型是明确标记为null类型。 这意味着您将无法在没有值的情况下初始化变量。 例如:

What do you get from all this extra work? Now that your types are more specific, TypeScript will be able to analyze your code flow and find potential bugs:

您从所有这些额外工作中得到什么? 现在您的类型更加具体,TypeScript将能够分析您的代码流并查找潜在的错误:

Sometimes you have to opt out of this feature. Maybe some external types are wrong, but you have no way to fix them or you want to gradually introduce this flag. You can always disable strictNullChecks by using the ! symbol.Any property access that has the !symbol will be ignored in this check:

有时您必须选择退出此功能。 也许某些外部类型是错误的,但是您无法修复它们,或者您希望逐步引入此标志。 您始终可以使用!禁用strictNullChecks ! symbol。任何具有!属性访问 此检查将忽略符号:

Only if you enable strictNullChecks will you be able to enable the next flag.

只有启用strictNullChecks您才能启用下一个标志。

strictPropertyInitialization (strictPropertyInitialization)

With strictPropertyInitialization, TypeScript will throw an error unless all class properties are initialized in the constructor or by a property initializer. This is used to help prevent unintentional access to undefined props in your code:

使用strictPropertyInitialization ,除非所有类属性都在构造函数中或由属性初始化程序初始化,否则TypeScript将引发错误。 这用于帮助防止意外访问代码中undefined道具:

Sometimes you can’t initialize in the class creation. For example, maybe you use an external service to fetch data. In these cases, you can ignore strictPropertyInitialization by using the ! symbol just like you used it for strictNullChecks:

有时您无法在类创建中进行初始化。 例如,也许您使用外部服务来获取数据。 在这些情况下,您可以使用!来忽略strictPropertyInitialization ! 符号,就像您将其用于strictNullChecks

strictFunctionTypes (strictFunctionTypes)

In TypeScript, argument types are bivariant (both covariant and contravariant), which is unsound (although you can now fix this in TypeScript 2.6 with --strictFunctionTypes or --strict).

在TypeScript中, 参数类型是双变量的 (协变和反变量),是不可靠的 (尽管您现在可以在TypeScript 2.6中使用--strictFunctionTypes--strict来解决此问题)。

Let’s look at a simple example to understand what it means:

让我们看一个简单的示例,以了解其含义:

In this example, we call forEach with another function that gets an HTMLElement even though querySelectorAll returns a list of Element (which HTMLElement extends). You can see that we access the element’s offsetHeight, a property that doesn’t exist on Element but only on HTMLElement.

在此示例中,即使querySelectorAll返回一个Element列表( HTMLElement扩展),我们也会使用另一个获取HTMLElement函数调用forEach 。 您可以看到我们访问了元素的offsetHeight ,该属性在Element上不存在,而仅在HTMLElement

Without strictFunctionTypes, this code will compile, but its types are wrong and can lead to potential bugs. If we turnstrictFunctionTypes on, we will get an error:

如果没有strictFunctionTypes ,则此代码将编译,但是其类型是错误的,并且可能导致潜在的错误。 如果打开strictFunctionTypes ,将收到错误消息:

Type ‘Element’ is missing the following properties from type ‘HTMLElement’ …

This basically means that we can’t decide that element is HTMLElement instead of Element because then we can use properties that only HTMLElement has inside our function, which is wrong.

这基本上意味着我们不能确定elementHTMLElement而不是Element因为那样我们就可以使用函数内部只有HTMLElement具有的属性,这是错误的。

strictBindCallApply (strictBindCallApply)

With the strictBindCallApply flag, the bind, call, and apply methods are strongly typed. Without this flag, you can mistakenly use these three functions with arguments that don’t match the function they are used on:

使用strictBindCallApply标志,将对bindcallapply方法进行强类型化。 如果没有此标志,则可能错误地将这三个函数的参数与使用它们的函数不匹配:

noImplicititThis (noImplicitThis)

This acts the same way as noImplicitAny, but for the this type. If you have a function that uses this, but the compiler can’t infer what the type of this is from the code, you will have an error. This can help catch bugs in compile time instead of in runtime. For example:

此行为与noImplicitAny相同,但对于this类型。 如果你有一个使用功能this ,但是编译器不能推断出的类型this是从代码,你将有一个错误。 这可以帮助在编译时而不是在运行时捕获错误。 例如:

In this example, we get a runtime error:

在此示例中,我们得到一个运行时错误:

Uncaught TypeError: Cannot read property ‘x’ of undefined.

We get an error because we called isEqual with the wrong this parameter (we lost the this binding when we assigned the function to another variable in line 11).

由于使用错误的this参数调用isEqual ,我们得到了一个错误(将函数分配给第11行的另一个变量时,我们失去了this绑定)。

If we had the noImplicitThis flag on, instead of a runtime error, we would get a compile-time error on line 6: ‘this’ implicitly has type ‘any’. We can fix this error by writing the this type explicitly, which will force us to fix the bug:

如果打开noImplicitThis标志,而不是运行时错误,我们将在第6行得到编译时错误: 'this' implicitly has type 'any' 。 我们可以通过显式编写this类型来修复此错误,这将迫使我们修复该错误:

结论 (Conclusion)

I hope you now understand strict mode and that you should use it in your code because the benefits are greater than the price — at least for new projects that don’t require migration.

我希望您现在了解严格的模式,并且应该在代码中使用它,因为这样做的好处大于价格,至少对于不需要迁移的新项目而言。

For existing projects, consider adding one strict flag at a time, making the migration more gradual.

对于现有项目,请考虑一次添加一个严格的标志,以使迁移更加逐步。

翻译自: https://medium.com/better-programming/how-typescripts-strict-mode-actually-fixes-typescript-736ba8108c85

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值