首页 > 建站教程 > JS、jQ、TS >  TypeScript中的感叹号正文

TypeScript中的感叹号

用作类型断言
identifier! 从 identifier 的类型里去除了 null 和 undefined
function broken(name: string | null): string {
  function postfix(epithet: string) {
    return name.charAt(0) + '.  the ' + epithet; // 错误, 'name' 可能是 null
  }
  name = name || "Bob";
  return postfix("great");
}

function fixed(name: string | null): string {
  function postfix(epithet: string) {
    return name!.charAt(0) + '.  the ' + epithet; // 正确
  }
  name = name || "Bob";
  return postfix("great");
}
本例使用了嵌套函数,因为编译器无法去除嵌套函数的null(除非是立即调用的函数表达式)。 因为它无法跟踪所有对嵌套函数的调用,尤其是你将内层函数做为外层函数的返回值。 如果无法知道函数在哪里被调用,就无法知道调用时name的类型。

检查未调用的函数
一个常见且危险的错误是:忘记调用一个函数,特别是当该函数不需要参数,或者它的命名容易被误认为是一个属性而不是函数时。
interface User {
    isAdministrator(): boolean;
    notify(): void;
    doNotDisturb?(): boolean;
}

// 之后…

// 有问题的代码,别用!
function doAdminThing(user: User) {
    // 糟了!
    if (user.isAdministrator) {
        sudo();
        editTheConfiguration();
    }
    else {
        throw new AccessDeniedError("User is not an admin");
    }
}
在这段代码中,我们忘了调用 isAdministrator,导致该代码错误地允许非管理员用户修改配置!

在 TypeScript 3.7 中,它会被识别成一个潜在的错误:
function doAdminThing(user: User) {
    if (user.isAdministrator) {
    //  ~~~~~~~~~~~~~~~~~~~~
    // error! This condition will always return true since the function is always defined.
    //        Did you mean to call it instead?
这个检查功能是一个破坏性变更,基于这个因素,检查会非常保守。 因此对这类错误的提示仅限于 if 条件语句中。当问题函数是可选属性、或未开启 strictNullChecks 选项、或该函数在 if 的代码块中有被调用,在这些情况下不会被视为错误:
interface User {
    isAdministrator(): boolean;
    notify(): void;
    doNotDisturb?(): boolean;
}

function issueNotification(user: User) {
    if (user.doNotDisturb) {
        // OK,属性是可选的
    }
    if (user.notify) {
        // OK,调用了该函数
        user.notify();
    }
}
如果你打算对该函数进行测试但不调用它,你可以修改它的类型定义,让它可能是 undefined/null,或使用 !! 来编写类似 if (!!user.isAdministrator) 的代码,表示代码逻辑确实是这样的。