严格模式与混杂模式如何区分_Angular V9 严格模式

f021c67c34e2a7cde2839687e0594917.png
twitter链接​twitter.com

4978dd60c1df12dcb10e38ecfc45a43c.png

在即将发布的 Angular V9 中,开发者可以在创建项目时通过添加 --strict 标签为项目增加更多类型检查机制。

ng new demoproject --strict

更完备的类型检查内容可以帮助开发更轻松的管控项目质量,减少意外。

启用严格模式后的项目的编译配置会增加如下内容:

baf42ba3d3d425d2ca7f6c281aa8e39e.png

noImplicitAny

在 typescript 中,如果你没有参数进行显示注释,typescript将会隐式地将参数标记为 any 类型,并执行后续的操作,虽然对 JavaScript 开发者而言,这是很常见的行为方式,但是缺乏类型检查可能会增加出现问题时 debug 的难度。

开启 noImplicitAny

typescript 将不再允许对参数的隐式 Any

function log(someArg) { // Error : someArg has an implicit `any` type
  sendDataToServer(someArg);
}

需要使用显式注释才可以通过编译

function log(someArg: number) {
  sendDataToServer(someArg);
}

如果确信不需要类型检查,则需要将参数显示注释为 any

function log(someArg: any) {
  sendDataToServer(someArg);
}

noImplicitReturns

确保每一个函数(包含函数中每一个逻辑分支)都都有显式的返回值(除非函数显式地将返回结果注释为 void)

getTotal(discount: number): number {
        if (discount) {
            const priceWithoutDiscount = this.product.unitPrice * this.quantity;
            const discountAmount = priceWithoutDiscount * discount;
            return priceWithoutDiscount - discountAmount;
        } else { 
          // We forgot about this branch!  
        }}

在使用 noImplicitReturns 标签的情况下,上述代码无法通过编译。

noImplicitThis

this 的错误用法,运行下述代码

class Rectangle {
    constructor(w, h) {
        this.w = w;
        this.h = h;
    }
    getAreaFunction() {
        return function() {
            return this.w * this.h;
        };
    }
}
let rectangle = new Rectangle(2, 5);
let areaFunction = rectangle.getAreaFunction();
let area = areaFunction();
console.log(area);
// this-wrong-use.ts

结果为

Cannot read property 'w' of undefined

上述代码中 areaFunction 被调用时,this 并没有指向 Rectangle 的实例。

事实上在运行时,this 的值依赖于函数被调用的方式:

  • 通过对象实例调用 obj.func()
  • 直接调用 func()

使用严格模式后,如果函数通过 func() 的方式直接调用,this 的值为 undefined

使用 noImplicitThis 后,typescript 会警告有关 this 的错误使用,效果如下

$ tsc --noImplicitThis this-wrong-use.ts
this-wrong-use.ts:12:19 - error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.

12            return this.w * this.h;
                     ~~~~

this-wrong-use.ts:12:28 - error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.

12            return this.w * this.h;

noFallthroughCasesInSwitch

使用 noFallthroughCasesInSwitch 进行 switch 声明校验。

请看如下功能代码:

enum SwitchEnum { 
    ONE, 
    TWO 
} 
 
function testEnumSwitch(value: SwitchEnum) : string { 
    let returnValue = ""; 
    switch(value) { 
        case SwitchEnum.ONE: 
            returnValue = "One"; 
        case SwitchEnum.TWO: 
            returnValue = "Two"; 
    } 
    return returnValue; 
} 

上述代码中,定义了一个名为 SwitchEnum 的 enum 类型数据;定义了一个名为 testEnumSwitch 的函数,接受一个 SwitchEnum 类型的参数 value,并返回 string 类型的结果。testEnumSwitch 函数中定义了一个名为 returnValue 的字符串类型变量并初始化为空字符串,使用 switch 声明逻辑将 returnValue 的值设置为 ”One“ 或 ”Two“,并最终将其作为结果返回。

上述代码在使用 noFallthroughCasesInSwitch 的情况下,会报出如下错误

error TS7029: Fallthrough case in switch. 

这代表着 typescript 识别出了上述代码中 switch 代码段的错误。

假设,上述函数接受的入参为 SwitchEnum.ONE, 那么按照期待的功能,returnValue 的值应当被设置为 ”One“ 并返回。但事实却是,swtich statement 的逻辑将会继续执行到第二个case,而将 returnValue 设置为 ”Two“。事实上,无论传入的参数内容几何,最终函数的返回结果都将是 ”two“。

正确的实现代码如下:

function testEnumSwitch(value: SwitchEnum) : string { 
    let returnValue = ""; 
    switch(value) { 
        case SwitchEnum.ONE: 
            returnValue = "One"; 
            break; 
        case SwitchEnum.TWO: 
            returnValue = "Two"; 
    } 
    return returnValue; 
} 

通过在 case 后增加 break 的方式避免 switch 逻辑 fall through。

借助于 noFallthroughCasesInSwitchtypescript 编译器正确地指出了 switch 语句中存在明显错误,避免了 switch statement logic falls through 的问题。

strictNullChecks

严格的 Null 校验。

在严格的 Null 校验模式下,nullundefined 只能用于特定类型的变量(只能用于自身和 any 类型的变量) 。

在常规的类型检查模式中,TT | undefined 可以被当做是同一个含义的泛型 (undefined 可以被视为 T 的子类型);但是在严格的 NULL 校验模式下,只有 T | undefined 才可以接受 undefined 的参数。

同样的规则也适用于 T | null

// Compiled with --strictNullChecks
let x: number;
let y: number | undefined;
let z: number | null | undefined;
x = 1;  // Ok
y = 1;  // Ok
z = 1;  // Ok
x = undefined;  // Error
y = undefined;  // Ok
z = undefined;  // Ok
x = null;  // Error
y = null;  // Error
z = null;  // Ok
x = y;  // Error
x = z;  // Error
y = x;  // Ok
y = z;  // Error
z = x;  // Ok
z = y;  // Ok

Assigned-before-use checking

在严格的 Null 校验模式下,编译器要求在每一个可能的代码路径中,对不包括 undefined 类型的局部变量,每次引用之前都需要明确赋值。

// Compiled with --strictNullChecks
let x: number;
let y: number | null;
let z: number | undefined;
x;  // Error, reference not preceded by assignment
y;  // Error, reference not preceded by assignment
z;  // Ok
x = 1;
y = null;
x;  // Ok
y;  // Ok

Optional parameters and properties

对于可选的参数/属性而言,即使你没有显示地要求对其进行 undefined 类型声明, 其类型会自动添加 undefined

// Compiled with --strictNullChecks
type T1 = (x?: number) => string;              // x has type number | undefined
type T2 = (x?: number | undefined) => string;  // x has type number | undefined

Non-null and non-undefined type guards

如果对象或函数的类型包含 null 或 undefined ,则访问属性或函数调用可能会产生编译错误。目前,type guards 已扩展为支持 Non-null 和 non-undefined 校验。

// Compiled with --strictNullChecks
declare function f(x: number): string;
let x: number | null | undefined;
if (x) {
    f(x);  // Ok, type of x is number here
}
else {
    f(x);  // Error, type of x is number? here
}
let a = x != null ? f(x) : "";  // Type of a is string
let b = x && f(x);  // Type of b is string | 0 | null | undefined

Non-null and non-undefined 类型校验必须使用 ==,!=,===, 或!== 操作符与 null 和 undefined 进行比较。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值