打字稿安全导航操作符(?。)或(!。)和null属性路径

时间:2016-10-25 10:57:43

标签: typescript

Angular2模板具有安全的运算符(?。),但在component.ts(typescript 2.0)中。安全导航操作员(!)无法正常工作。

示例:

此TypeScript

if (a!.b!.c) { }

编译到这个JavaScript

if (a.b.c) { }

但是当我运行它时,我得到了以下错误:

  

无法阅读财产' b'未定义的

还有其他选择:

if (a && a.b && a.b.c) { }

6 个答案:

答案 0 :(得分:86)

目前在打字稿中没有安全导航操作符(仍在discussion中)。

!.是非空断言运算符 - 它只是说键入检查器确定a不是null或{{1 }}。

更多信息here

答案 1 :(得分:17)

您可以尝试编写这样的自定义函数。

该方法的主要优点是类型检查和部分智能感知。

export function nullSafe<T, 
    K0 extends keyof T, 
    K1 extends keyof T[K0],
    K2 extends keyof T[K0][K1],
    K3 extends keyof T[K0][K1][K2],
    K4 extends keyof T[K0][K1][K2][K3],
    K5 extends keyof T[K0][K1][K2][K3][K4]>
    (obj: T, k0: K0, k1?: K1, k2?: K2, k3?: K3, k4?: K4, k5?: K5) {
    let result: any = obj;

    const keysCount = arguments.length - 1;
    for (var i = 1; i <= keysCount; i++) {
        if (result === null || result === undefined) return result;
        result = result[arguments[i]];
    }

    return result;
}

和用法(最多支持5个参数,可以扩展):

nullSafe(a, 'b', 'c');

playground上的示例。

答案 2 :(得分:15)

另一种使用外部库的替代方法是来自_.has()Lodash

E.g。

_.has(a, 'b.c')

等于

(a && a.b && a.b.c)

编辑: 如评论中所述,使用此方法时会丢失Typescript的类型推断。 例如。假设一个人的对象被正确输入,如果z未被定义为对象b的字段,则会得到(a&amp;&amp; a.b&amp;&amp; a.b.z)的编译错误。但是使用_.has(a,'b.z'),就不会出现错误。

答案 3 :(得分:14)

自TypeScript 3.7发布以来,您现在可以使用可选链接。

属性示例:

let x = foo?.bar.baz();

这等同于:

let x = (foo === null || foo === undefined) ?
    undefined :
    foo.bar.baz();

此外,您可以致电:

可选电话

function(otherFn: (par: string) => void) {
   otherFn.?("some value");
}

otherFn仅在otherFn不等于null或未定义的情况下才会被调用

在IF语句中使用可选链接

此:

if (someObj && someObj.someProperty) {
    // ...
}

现在可以替换为此

if (someObj?.someProperty) {
    // ...
}

参考https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html

答案 4 :(得分:2)

基于@Pvl的答案,如果您使用覆盖,则还可以在返回值中包括类型安全性:

Usage: userdel [options] LOGIN

Options:
  -f, --force                   force removal of files,
                                even if not owned by user
  -h, --help                    display this help message and exit
  -r, --remove                  remove home directory and mail spool
  -R, --root CHROOT_DIR         directory to chroot into
  -Z, --selinux-user            remove any SELinux user mapping for the user

playground上的示例。

答案 5 :(得分:2)

一个名为 ts-optchain 的新库提供了此功能,并且与lodash的解决方案不同,它还可以确保您的类型安全,这里是使用方法的示例(摘自自述文件) ):

import { oc } from 'ts-optchain';

interface I {
  a?: string;
  b?: {
    d?: string;
  };
  c?: Array<{
    u?: {
      v?: number;
    };
  }>;
  e?: {
    f?: string;
    g?: () => string;
  };
}

const x: I = {
  a: 'hello',
  b: {
    d: 'world',
  },
  c: [{ u: { v: -100 } }, { u: { v: 200 } }, {}, { u: { v: -300 } }],
};

// Here are a few examples of deep object traversal using (a) optional chaining vs
// (b) logic expressions. Each of the following pairs are equivalent in
// result. Note how the benefits of optional chaining accrue with
// the depth and complexity of the traversal.

oc(x).a(); // 'hello'
x.a;

oc(x).b.d(); // 'world'
x.b && x.b.d;

oc(x).c[0].u.v(); // -100
x.c && x.c[0] && x.c[0].u && x.c[0].u.v;

oc(x).c[100].u.v(); // undefined
x.c && x.c[100] && x.c[100].u && x.c[100].u.v;

oc(x).c[100].u.v(1234); // 1234
(x.c && x.c[100] && x.c[100].u && x.c[100].u.v) || 1234;

oc(x).e.f(); // undefined
x.e && x.e.f;

oc(x).e.f('optional default value'); // 'optional default value'
(x.e && x.e.f) || 'optional default value';

// NOTE: working with function value types can be risky. Additional run-time
// checks to verify that object types are functions before invocation are advised!
oc(x).e.g(() => 'Yo Yo')(); // 'Yo Yo'
((x.e && x.e.g) || (() => 'Yo Yo'))();