[typescript] 안전한 탐색 연산자 (?.) 또는 (!.) 및 null 속성 경로를 입력합니다.

Angular2 템플릿에서 안전한 연산자 ?.는 작동하지만 component.tsTypeScript 2.0 을 사용 하지는 않습니다 . 또한 안전한 탐색 연산자 (!.)가 작동하지 않습니다.

예를 들면 …

이 TypeScript

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

이 JavaScript로 컴파일됩니다.

if (a.b.c) { }

하지만 실행하면 다음 오류가 발생합니다.

정의되지 않은 속성 ‘b’를 읽을 수 없습니다.

다음에 대한 대안이 있습니까?

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



답변

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) {
    // ...
}

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


답변

!되는 null 이외의 주장 연산자 (후 수정 식) – 그냥 것을 검사기를 입력 할 말을 당신이있어 그 확실 a하지 않다 nullundefined.

작업 a!awith nullundefinedexcluded 유형의 값을 생성합니다.


선택적 연결은 마침내 typescript 로 만들었 습니다. ( 3.7 ) ?

선택적 연결 연산자를 사용 ?.하면 체인의 각 참조가 유효한지 명시 적으로 유효성을 검사 할 필요없이 연결된 개체의 체인 내 깊은 곳에있는 속성 값을 읽을 수 있습니다. 이 ?.연산자 .는 참조가 nullish ( null또는 undefined) 인 경우 오류를 발생시키는 대신 표현식이 반환 값으로 단락 된다는 점을 제외 하면 연결 연산자 와 유사하게 작동합니다 undefined. 함수 호출과 함께 사용할 때 undefined주어진 함수가 존재하지 않으면 반환 합니다.

구문 :

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

주의 :

선택적 연결은 할당의 왼쪽에서 유효하지 않습니다.

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


답변

최신 정보:

3.7 릴리스 범위에서 계획 됨
https://github.com/microsoft/TypeScript/issues/33352


이와 같은 사용자 지정 함수를 작성해 볼 수 있습니다.

이 접근 방식의 주요 장점은 유형 검사와 부분적인 지능입니다.

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');

놀이터의 예 .


답변

외부 라이브러리를 사용하는 또 다른 대안은 _.has () 에서 Lodash .

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

동일하다

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

편집 : 주석에서 언급 했듯이이 방법을 사용할 때 Typescript의 유형 유추를 잃습니다. 예를 들어 개체가 올바르게 입력되었다고 가정하면 z가 개체 b의 필드로 정의되지 않으면 (a && ab && abz)와 함께 컴파일 오류가 발생합니다. 그러나 _.has (a, ‘b.z’)를 사용하면 해당 오류가 발생하지 않습니다.


답변

ts-optchain 이라는 새 라이브러리 는이 기능을 제공하며 lodash의 솔루션과 달리 유형을 안전하게 유지합니다. 다음은 사용 방법에 대한 샘플입니다 (readme에서 가져옴).

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'))();


답변

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

놀이터의 예 .


답변