typescript 打字稿安全导航运算符 ( ?. ) 或 (!.) 和空属性路径

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40238144/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:25:07  来源:igfitidea点击:

Typescript the safe navigation operator ( ?. ) or (!.) and null property paths

typescript

提问by Emerceen

In Angular2 templates safe operator ?.works, but not in component.tsusing TypeScript 2.0. Also, safe navigation operator (!.) doesn't work.

在 Angular2 模板中,安全运算符?.有效,但在component.ts使用 TypeScript 2.0 时无效。此外,安全导航运算符 (!.) 不起作用。

For example...

例如...

This TypeScript

这个打字稿

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

compiles to this JavaScript

编译成这个 JavaScript

if (a.b.c) { }

But when I run it, I get the follow error:

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

Cannot read property 'b' of undefined

无法读取未定义的属性“b”

Is there any alternative to the following?

有没有以下替代方案?

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

采纳答案by Przemek Struciński

Since TypeScript 3.7 was released you can use optional chaining now.

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

Property example:

属性示例:

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

This is equvalent to:

这相当于:

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

Moreover you can call:

此外,您可以致电:

Optional Call

可选电话

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

otherFn will be called only if otherFn won't be equal to null or undefined

仅当 otherFn 不等于 null 或 undefined 时才会调用 otherFn

Usage optional chaining in IF statement

在 IF 语句中使用可选链

This:

这个:

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

can be replaced now with this

现在可以用这个替换

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

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

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

回答by Aleksey L.

!is non-null assertion operator(post-fix expression) - it just saying to type checker that you'resure that ais not nullor undefined.

!is non-null assertion operator(post-fix expression) - 它只是告诉类型检查器确定它a不是nullor undefined

the operation a!produces a value of the type of awith nulland undefinedexcluded

该操作a!产生一个类型为awithnullundefinedexclude 的值



Optional chainingfinally madeit to typescript (3.7)

可选链接最终成为打字稿(3.7

The optional chaining operator ?.permits reading the value of a property located deep within a chain of connected objects without having to expressly validate that each reference in the chain is valid. The ?.operator functions similarly to the .chaining operator, except that instead of causing an error if a reference is nullish (nullor undefined), the expression short-circuits with a return value of undefined. When used with function calls, it returns undefinedif the given function does not exist.

可选链运算符?.允许读取位于连接对象链深处的属性值,而无需明确验证链中的每个引用是否有效。的?.操作者的功能同样地.链接操作,不同之处在于代替如果参考是nullish(导致错误nullundefined),则表达式短路用的返回值undefined。当与函数调用一起使用时,undefined如果给定的函数不存在,则返回。

Syntax:

语法

obj?.prop // Accessing object's property
obj?.[expr] // Optional chaining with expressions
arr?.[index] // Array item access with optional chaining
func?.(args) // Optional chaining with function calls

Pay attention:

注意

Optional chaining is not valid on the left-hand side of an assignment

可选链在赋值的左侧无效

const object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment

回答by NaN

Update:

更新:

Planned in the scope of 3.7 release
https://github.com/microsoft/TypeScript/issues/33352

计划在 3.7 版本范围内发布
https://github.com/microsoft/TypeScript/issues/33352



You can try to write a custom function like that.

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

The main advantage of the approach is a type-checking and partial intellisense.

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

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;
}

And usage (supports up to 5 parameters and can be extended):

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

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

Example on playground.

操场上的例子。

回答by TiaanM

Another alternative that uses an external library is _.has()from Lodash.

使用外部库另一个替代方案是_.has()Lodash

E.g.

例如

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

is equal to

等于

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

EDIT: As noted in the comments, you lose out on Typescript's type inference when using this method. E.g. Assuming that one's objects are properly typed, one would get a compilation error with (a && a.b && a.b.z) if z is not defined as a field of object b. But using _.has(a, 'b.z'), one would not get that error.

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

回答by VitalyB

A new library called ts-optchainprovides this functionality, and unlike lodash' solution, it also keeps your types safe, here is a sample of how it is used (taken from the readme):

一个名为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'))();

回答by Alec

Building on @Pvl's answer, you can include type safety on your returned value as well if you use overrides:

以@Pvl 的回答为基础,如果您使用覆盖,您也可以在返回值中包含类型安全:

function dig<
  T,
  K1 extends keyof T
  >(obj: T, key1: K1): T[K1];

function dig<
  T,
  K1 extends keyof T,
  K2 extends keyof T[K1]
  >(obj: T, key1: K1, key2: K2): T[K1][K2];

function dig<
  T,
  K1 extends keyof T,
  K2 extends keyof T[K1],
  K3 extends keyof T[K1][K2]
  >(obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3];

function dig<
  T,
  K1 extends keyof T,
  K2 extends keyof T[K1],
  K3 extends keyof T[K1][K2],
  K4 extends keyof T[K1][K2][K3]
  >(obj: T, key1: K1, key2: K2, key3: K3, key4: K4): T[K1][K2][K3][K4];

function dig<
  T,
  K1 extends keyof T,
  K2 extends keyof T[K1],
  K3 extends keyof T[K1][K2],
  K4 extends keyof T[K1][K2][K3],
  K5 extends keyof T[K1][K2][K3][K4]
  >(obj: T, key1: K1, key2: K2, key3: K3, key4: K4, key5: K5): T[K1][K2][K3][K4][K5];

function dig<
  T,
  K1 extends keyof T,
  K2 extends keyof T[K1],
  K3 extends keyof T[K1][K2],
  K4 extends keyof T[K1][K2][K3],
  K5 extends keyof T[K1][K2][K3][K4]
  >(obj: T, key1: K1, key2?: K2, key3?: K3, key4?: K4, key5?: K5):
  T[K1] |
  T[K1][K2] |
  T[K1][K2][K3] |
  T[K1][K2][K3][K4] |
  T[K1][K2][K3][K4][K5] {
    let value: any = obj && obj[key1];

    if (key2) {
      value = value && value[key2];
    }

    if (key3) {
      value = value && value[key3];
    }

    if (key4) {
      value = value && value[key4];
    }

    if (key5) {
      value = value && value[key5];
    }

    return value;
}

Example on playground.

操场上的例子。