Typescript가?를 지원합니까? 운영자? (그리고 그것이 무엇입니까?)


336

Typescript가 현재 안전한 탐색 연산자를 지원합니까 (또는 계획이 있습니까)?.

즉 :

var thing = foo?.bar
// same as:
var thing = (foo) ? foo.bar : null;

또한이 연산자의 더 일반적인 이름이 있습니까? (구글 적으로 구글하기가 어렵습니다).


3
@ mattytommo 당신은 그것을 C #에서 가지고 있는데, 그것은 null 병합 연산자라고하며 ?? 구문 weblogs.asp.net/scottgu/archive/2007/09/20/…
basarat

2
@BasaratAli은 불행히도, 유착은 괜찮지 property ?? property2만, 당신이 시도하는 경우 property.company ?? property1.companypropertynull입니다, 당신은 얻을 것NullReferenceException
mattytommo

1
@mattytommo 감사합니다. 이제 '?.' 실제로 체인의 모든 null 참조를 흡수합니다. 단.
basarat

9
@ mattytommo 이것은 현재 C #에 존재합니다. msdn.microsoft.com/en-us/library/dn986595.aspx
Highmastdon

9
우리를 방문한 Microsoft 담당자는 Elvis 운영자라고 불렀습니다. 물음표는 Elvis의 머리카락과 그가 부르는 마이크처럼 보입니다.
Zymotik

답변:


167

업데이트 : TypeScript 3.7부터 지원되며 선택적 체인 이라고합니다 : https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining

TypeScript 언어 사양 에서 그것에 대한 참조를 찾을 수 없습니다 .

CoffeeScript에서이 연산자를 호출 할 때까지이를 존재 연산자 (특히, 존재 연산자 의 "접근 변형 자")라고합니다.

에서 연산자에 커피 스크립트의 설명서 :

실재 연산자의 접근 자 변형을 ?.사용하여 일련의 속성에서 null 참조를 흡수 할 수 있습니다. .기본 값이 null 이거나 정의되지 않은 경우 도트 접근 자 대신 사용하십시오 .

따라서 실재 연산자접근 자 변형 이이 연산자를 참조하는 적절한 방법 인 것 같습니다. TypeScript는 현재 그것을 지원하지 않는 것으로 보입니다 ( 다른 사람들 이이 기능에 대한 욕구를 표현 했지만 ).


28
"실존 연산자의 접근 자 변형" 당연히. 너무 까다 롭고 잊을 수는 거의 없습니다. :). 매우 철저한 답변에 감사드립니다.
Marty Pitt

1
@MartyPitt 물론! 나는 a) 이와 같은 연산자를 더 많이 채택하고 (C # please!) b) 더 나은 이름 (링크 된 블로그 게시물의 "안전한 탐색"연산자가 좋은 링을 가지고 있음)을보고 싶다는 데 동의합니다.
Donut

2
Angular는 이것을 템플릿으로 구현합니다 : angular.io/guide/…
Enzoaeneas

5
다른 언어로는 "Elvis"연산자
k0enf0rNL

4
그것은 타이프 라이터 3.7.0 (대한 발표 것 github.com/microsoft/TypeScript/issues/... )
c_froehlich

146

단일만큼 좋지는 않지만 작동합니다.

var thing = foo && foo.bar || null;

원하는만큼 &&을 (를) 사용할 수 있습니다.

var thing = foo && foo.bar && foo.bar.check && foo.bar.check.x || null;

33
&&는 진술이 참인 한 평가합니다. true이면 마지막 값을 반환합니다. False이면 False로 평가 된 첫 번째 값을 반환합니다. 0, null, false 등일 수 있습니다. || true로 평가되는 첫 번째 값을 반환합니다.
A. KR

34
막대가 정의되어 있지만 부울 false 또는 0과 같이 false로 평가되면 제대로 작동하지 않습니다.
mt_serg

96

이는 ECMAScript 선택적 체인 사양에 정의되어 있으므로 이에 대해 논의 할 때 선택적 체인을 참조해야 합니다. 아마도 구현 :

const result = a?.b?.c;

이것의 길고 짧은 것은 TypeScript 팀이 ECMAScript 사양이 강화되기를 기다리고 있기 때문에 향후 구현이 중단되지 않을 수 있다는 것입니다. 만약 그들이 지금 무언가를 구현한다면, ECMAScript가 그들의 사양을 재정의한다면 큰 변화가 필요할 것입니다.

선택적 체인 사양 참조

어떤 것이 표준 JavaScript가 될 수없는 경우 TypeScript 팀은 적합하다고 생각되는대로 구현할 수 있지만 향후 ECMAScript 추가를 위해 다른 많은 기능과 마찬가지로 조기 액세스를 제공하더라도 의미를 보존하려고합니다.

바로 가기

따라서 다음과 같은 유형 변환을 포함하여 모든 JavaScript 펑키 연산자를 사용할 수 있습니다.

var n: number = +myString; // convert to number
var b: bool = !!myString; // convert to bool

수동 솔루션

그러나 다시 질문으로 돌아갑니다. JavaScript (유형 TypeScript)에서 비슷한 작업을 수행하는 방법에 대한 모호한 예가 있지만 실제로 그 기능이 우아하다는 것은 아닙니다.

(foo||{}).bar;

그래서 경우가 foo있습니다 undefined결과 undefined및 경우 foo정의라는 이름의 속성이되는 bar값을 가지고, 결과는 그 값입니다.

나는 넣어 JSFiddle에 예 .

더 긴 예제에서는 상당히 스케치처럼 보입니다.

var postCode = ((person||{}).address||{}).postcode;

체인 기능

사양이 아직 공개되지 않은 상태에서 더 짧은 버전을 원한다면 필자는이 방법을 사용합니다. 체인을 만족시킬 수 없거나 null / undefined로 끝나는 경우 표현식을 평가하고 기본값을 반환합니다 ( !=여기서는 중요합니다. 여기서 약간의 긍정적 인 저글링을 원하므로 사용하고 싶지 않습니다!== ).

function chain<T>(exp: () => T, d: T) {
    try {
        let val = exp();
        if (val != null) {
            return val;
        }
    } catch { }
    return d;
}

let obj1: { a?: { b?: string }} = {
    a: {
        b: 'c'
    }
};

// 'c'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = {
    a: {}
};

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = {};

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

obj1 = null;

// 'Nothing'
console.log(chain(() => obj1.a.b, 'Nothing'));

1
흥미로운하지만 내 경우에는 (this.loop || {}).nativeElementProperty 'nativeElement' does not exist on type '{}'. any this.loop대해서 typeof angular.io/api/core/ElementRef
kuncevic.dev

@Kuncevic-1) 대신에 호환되는 기본값을 제공 {}하거나 2) 형식 어설 션을 사용하여 컴파일러를 침묵 시켜야합니다 .
Fenton

foo실제 유용한 객체 라고 가정하십시오 . (foo || {}).bar일반적으로 {}와 같은 유형이 아니기 때문에 일반적으로 유형 스크립트에서 컴파일 되지 않습니다 foo. 그것은 @VeganHunter의 솔루션이 피하려고하는 문제입니다.
Simon_Weaver 5

1
@Simon_Weaver (foo || {bar}). bar는 컴파일러가 원활하게 실행되도록하고 자세한 정보가 허용된다고 생각합니다.
하프

바이 가장 가능성이되지 않을 것 변수로 정의 된 경우 @harps 실제로는 컴파일
Simon_Weaver

82

업데이트 : 예, 이제 지원됩니다!

방금 TypeScript 3.7과 함께 출시되었습니다 : https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/

옵션 체인 이라고합니다 : https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/#optional-chaining

그것으로 다음과 같이 :

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

다음과 같습니다.

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

이전 답변

당신이 당신의 의견 / 욕망을 음성 수 GitHub의에이를위한 오픈 기능 요청이 있습니다 : https://github.com/Microsoft/TypeScript/issues/16


36

2019 년 11 월 13 일 수정!

2019 년 11 월 5 일 현재 TypeScript 3.7이 출시되었으며 이제 ?. 선택적 체인 연산자 🎉🎉🍾🍾🎉 !!!를 지원 합니다 !!!

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


역사적인 목적으로 만 :

편집 : fracz 의견 덕분에 답변을 업데이트했습니다.

TypeScript 2.0 출시 (C #의 Safe Navigator) !.와 동일하지 않음?.

자세한 내용은이 답변을 참조하십시오.

https://stackoverflow.com/a/38875179/1057052

이것은 컴파일러에게 그 값이 널 (null)이거나 정의되지 않았 음을 알려줍니다. 이 것 없는 값이 null이거나 정의되어 있는지 확인하세요.

TypeScript 널이 아닌 어설 션 연산자

// Compiled with --strictNullChecks
function validateEntity(e?: Entity) {
    // Throw exception if e is null or invalid entity
}

function processEntity(e?: Entity) {
    validateEntity(e);
    let s = e!.name;  // Assert that e is non-null and access name
}

4
값이 정의 되었다고 주장? 하기 때문에 동일하지 않습니다 . 자동 실패 / 거짓으로 평가됩니다. 어쨌든 알아 ?
fracz 2011

1
이제 생각해 보았습니다 ...이 대답은 C # 연산자가 수행하는 "안전한 탐색"을 수행하지 않기 때문에 무의미합니다.
Jose A

5
그래도 내 질문에 대답했습니다. 나는 알고 있었다?. c #에서 typescript로 시도했습니다. 그것은 효과가 없었지만 나는 그것을 보았다!. 존재했지만 그것이 무엇을했는지 몰랐습니다. 나는 그것이 같은지 궁금해하고 Google 검색을 수행 하고이 질문에 대한 길을 찾았습니다.
Llewey

11

Elvis (?.) 옵션 체인 연산자는 TypeScript 3.7에서 지원됩니다.

이를 사용하여 널값을 확인할 수 있습니다 cats?.miows. cats가 널이거나 정의되지 않은 경우 널을 리턴합니다.

선택적 메소드 호출에 사용할 수도 cats.doMiow?.(5)있습니다. 존재하는 경우 doMiow를 호출합니다.

속성 액세스도 가능합니다 : cats?.['miows'].

참조 : https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-beta/


저를 정정하십시오. 그러나 Elvis 운영자는 최소한 Kotlin에 ?:있습니다. 당신은 참조가 있습니까?
08:24에


1
- 그것은 일반 JS 곧 지원 될 것 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Mottie

1
타이프 스크립트 3.7 버전의 발표는 언급 : devblogs.microsoft.com/typescript/announcing-typescript-3-7
기요 Balássy

10

?.TypeScript 버전 2.0 에서는 연산자 가 지원되지 않습니다 .

그래서 나는 다음 기능을 사용합니다 :

export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
    if (typeof someObject === 'undefined' || someObject === null)
        return defaultValue;
    else
        return someObject;
}

사용법은 다음과 같습니다.

o(o(o(test).prop1).prop2

또한 기본값을 설정할 수 있습니다.

o(o(o(o(test).prop1).prop2, "none")

Visual Studio에서 IntelliSense와 잘 작동합니다.


1
이것이 바로 내가 찾던 것입니다! typescript 2.1.6에서 작동합니다.
Rajab Shakirov

5
또는 당신은 그것을 부를 수 elvis<T>;-)
Simon_Weaver

3
Simon_Weaver, 나는 "슬픈 광대"를 호출 : O (
VeganHunter

5

드디어 왔어요!

다음은 몇 가지 예입니다.

// properties
foo?.bar
foo?.bar()
foo?.bar.baz()
foo?.bar?.baz()

// indexing
foo?.[0]
foo?.['bar']

// check if a function is defined before invoking
foo?.()
foo.bar?.()
foo?.bar?.()

그러나 가정과 정확히 동일하게 작동하지는 않습니다.

평가하는 대신

foo?.bar

이 작은 코드 스 니펫에 우리는 모두 쓰는 데 익숙합니다.

foo ? foo.bar : null

실제로 평가

(foo === null || foo === undefined) ?
    undefined :
    foo.bar

빈 문자열, 0 또는 false와 같은 모든 잘못된 값에 작동합니다.

왜 컴파일하지 않는지에 대한 설명이 없습니다. foo == null


3

Phonetradr에서 작업하는 동안이 util 메소드를 작성 하여 Typescript를 사용하여 딥 속성에 안전하게 입력 할 수 있습니다.

/**
 * Type-safe access of deep property of an object
 *
 * @param obj                   Object to get deep property
 * @param unsafeDataOperation   Function that returns the deep property
 * @param valueIfFail           Value to return in case if there is no such property
 */
export function getInSafe<O,T>(obj: O, unsafeDataOperation: (x: O) => T, valueIfFail?: any) : T {
    try {
        return unsafeDataOperation(obj)
    } catch (error) {
        return valueIfFail;
    }
}

//Example usage:
getInSafe(sellTicket, x => x.phoneDetails.imeiNumber, '');

//Example from above
getInSafe(foo, x => x.bar.check, null);


멋있는!! 경고가 있습니까? 내가 쓰기에 약 20 게터와 래퍼 클래스를 가지고, 그들 모두는 반환의 다음과 같은 유형이 - 그리고 모든 필드가 null 체크해야return this.entry.fields.featuredImage.fields.file.url;
Drenai

유일한 경고는 성능에 영향을 줄 수 있지만 다양한 JIT 사용자가이를 처리하는 방법에 대해 이야기 할 자격이 없습니다.
레이 Suelzer

2

일반적으로이 방법을 권장하지는 않지만 (성능 문제를 조심하십시오) 스프레드 연산자를 사용하여 객체를 얕게 복제 한 다음 속성에 액세스 할 수 있습니다.

 const person = { personId: 123, firstName: 'Simon' };
 const firstName = { ...person }.firstName;

'firstName'의 유형이 '전파'되었기 때문에 작동합니다.

find(...)null을 반환 할 수 있는 표현식이 있고 단일 속성이 필요할 때 가장 자주 사용 합니다.

 // this would cause an error (this ID doesn't exist)
 const people = [person];
 const firstName2 = people.find(p => p.personId == 999).firstName;

 // this works - but copies every property over so raises performance concerns
 const firstName3 = { ...people.find(p => p.personId == 999) }.firstName;

typescript가 형식을 유추하는 방식과 관련된 일부 경우가있을 수 있으며 컴파일되지는 않지만 일반적으로 작동합니다.



0

이전에 대답했듯이, 현재도 여전히 고려되고 있지만 지금까지 몇 년 동안 물에서 죽었습니다 .

기존 답변을 바탕으로 생각할 수 있는 가장 간결한 수동 버전이 있습니다.

jsfiddle

function val<T>(valueSupplier: () => T): T {
  try { return valueSupplier(); } catch (err) { return undefined; }
}

let obj1: { a?: { b?: string }} = { a: { b: 'c' } };
console.log(val(() => obj1.a.b)); // 'c'

obj1 = { a: {} };
console.log(val(() => obj1.a.b)); // undefined
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

obj1 = {};
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

obj1 = null;
console.log(val(() => obj1.a.b) || 'Nothing'); // 'Nothing'

누락 된 속성 오류로 인해 자동으로 실패합니다. 기본값을 결정하는 표준 구문으로 돌아가며 완전히 생략 할 수 있습니다.


이것은 간단한 경우에 효과적이지만 함수 호출과 같은 더 복잡한 작업이 필요하고 결과의 속성에 액세스하면 다른 오류도 삼킨다. 나쁜 디자인.

위의 경우 여기에 게시 된 다른 답변의 최적화 된 버전이 더 나은 옵션입니다.

jsfiddle

function o<T>(obj?: T, def: T = {} as T): T {
    return obj || def;
}

let obj1: { a?: { b?: string }} = { a: { b: 'c' } };
console.log(o(o(o(obj1).a)).b); // 'c'

obj1 = { a: {} };
console.log(o(o(o(obj1).a)).b); // undefined
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

obj1 = {};
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

obj1 = null;
console.log(o(o(o(obj1).a)).b || 'Nothing'); // 'Nothing'

더 복잡한 예 :

o(foo(), []).map((n) => n.id)

다른 방법으로 가서 Lodash '와 같은 것을 사용할 수도 있습니다 _.get(). 간결하지만 컴파일러는 사용 된 속성의 유효성을 판단 할 수 없습니다.

console.log(_.get(obj1, 'a.b.c'));

0

아직 (2019 년 9 월 현재), "안전한 탐색 연산자" 가 이제 Stage 3 에 있으므로 TypeScript에서 구현되고 있습니다.

이 문제를보고 업데이트하십시오.

https://github.com/microsoft/TypeScript/issues/16

몇몇 엔진에는 초기 구현이 있습니다.

JSC : https://bugs.webkit.org/show_bug.cgi?id=200199

V8 : https://bugs.chromium.org/p/v8/issues/detail?id=9553

SM : https://bugzilla.mozilla.org/show_bug.cgi?id=1566143

( https://github.com/tc39/proposal-optional-chaining/issues/115#issue-475422578을 통해 )

지금 지원하기 위해 플러그인을 설치할 수 있습니다 :

npm install --save-dev ts-optchain

tsconfig.json에서 :

// tsconfig.json
{
    "compilerOptions": {
        "plugins": [
            { "transform": "ts-optchain/transform" },
        ]
    },
}

6 개월 정도 지나면이 답변이 만료 될 것으로 예상되지만 그 동안 누군가에게 도움이 되길 바랍니다.


-1

_.get(obj, 'address.street.name')유형이없는 JavaScript에 적합합니다. 그러나 TypeScript 에는 실제 Elvis 연산자 가 필요 합니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.