Typescript에서! 멤버를 역 참조 할 때 (느낌표 / 뱅) 연산자?


453

tslint 규칙의 소스 코드를 볼 때 다음과 같은 진술을 보았습니다.

if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    return;
}

!뒤에 연산자를 주목하십시오 node.parent. 흥미 롭습니다!

먼저 현재 설치된 TS (1.5.3) 버전으로 파일을 로컬로 컴파일하려고했습니다. 결과 오류는 뱅의 정확한 위치를 가리 켰습니다.

$ tsc --noImplicitAny memberAccessRule.ts 
noPublicModifierRule.ts(57,24): error TS1005: ')' expected.

다음으로 최신 TS (2.1.6)로 업그레이드하여 문제없이 컴파일했습니다. TS 2.x의 기능인 것 같습니다. 그러나 트랜스 필은 강타를 완전히 무시하여 다음 JS를 생성했습니다.

if (node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    return;
}

내 Google fu는 지금까지 실패했습니다.

TS의 느낌표 연산자는 무엇이며 어떻게 작동합니까?

답변:


691

이것이 null이 아닌 어설 션 연산자입니다. 그것은 컴파일러에게 할 수있는 방법이다 "이 표현이 될 수 없다 null거나 undefined그래서 존재의 가능성에 대해 불평하지 않는, 여기 nullundefined." 때로는 유형 검사기가 자체 결정을 할 수 없습니다.

여기에 설명되어 있습니다 :

새로운 !post-fix expression operator는 타입 체커가 그 사실을 결론 지을 수없는 상황에서 피연산자가 널이 아니며 정의되지 않은 것을 주장하는데 사용될 수있다. 특히, 조작 x!xwith nullundefinedexclude 유형의 값을 생성합니다 . 형태의 주장 비슷한 유형 <T>xx as T상기 !비 - 널 어서 오퍼레이터는 단순히 발광 자바 스크립트 코드를 제거한다.

나는 그 설명에서 "어설 션"이라는 용어를 잘못 사용하는 것을 발견했다. 테스트를 수행 한다는 의미가 아니라 개발자가 주장하고 있다는 의미에서 "어설 션"입니다 . 마지막 줄은 실제로 JavaScript 코드가 생성되지 않음을 나타냅니다.


102
'어설 션'모호성에 대한 좋은 전화.
Estus Flask

8
좋은 설명입니다. console.assert()변수를 추가하기 전에 해당 변수에 대해 수행하는 것이 좋습니다 !. add !는 컴파일러에게 널 검사를 무시하도록 지시 하기 때문에 Javascript에서 noop로 컴파일됩니다. 따라서 변수가 널이 아닌지 확실하지 않으면 명시 적 어설 션 검사를 수행하는 것이 좋습니다.
Jayesh

12
동기 부여 예제 : dict.has(key) ? dict.get(key) : 'default';TS 컴파일러 와 같은 코드와 함께 새로운 ES 맵 유형을 사용 하면 get호출이 null / 정의되지 않음을 반환 하지 않는다고 유추 할 수 없습니다 . dict.has(key) ? dict.get(key)! : 'default';유형을 올바르게 좁 힙니다.
kitsu.eb

1
Elvis 연산자가 이진 연산자를 참조하는 방법과 같이이 연산자에 대한 속어가 있습니까?
ebakunin

@Jayesh console.assert () 모범 사례에서 확장 할 수 있습니까? 예를 게시 할 수 있습니까?
Christopher Francisco

168

루이스의 대답은 훌륭하지만 간결하게 요약하려고 노력했습니다.

뱅 연산자는 컴파일러가 "널 (null) 아님"제약 조건을 일시적으로 완화하도록 요구합니다. 그것은 컴파일러에게 "개발자로서이 변수가 현재 널 (null)이 될 수 없다는 것을 당신보다 잘 알고 있습니다"라고 말합니다.


85
그런 다음 개발자로서 엉망입니다.
Mike Chamberlain

9
또는 컴파일러로서 엉망입니다. 생성자가 속성을 초기화하지 않지만 수명주기 후크에서 속성을 초기화하면 컴파일러에서이를 인식하지 못합니다.
Mukus

26
이것은 TS 컴파일러의 책임이 아닙니다. 다른 언어 (예 : C #)와 달리 JS (및 TS)는 사용하기 전에 변수를 초기화 할 것을 요구하지 않습니다. 또는 JS에서 다른 방법으로 보려고 var또는 let로 선언 되거나 암시 적으로 초기화 된 모든 변수 undefined. 또한 클래스 인스턴스 속성을 그대로 선언 할 수 있으므로 class C { constructor() { this.myVar = undefined; } }완벽하게 합법적입니다. 마지막으로 수명주기 후크는 프레임 워크에 따라 다릅니다. 예를 들어 Angular와 React는 다르게 구현합니다. 따라서 TS 컴파일러는 이에 대해 추론 할 수 없습니다.
Mike Chamberlain 님

1
TS에서 제어 흐름 기반 유형 분석의 굉장함을 고려할 때 뱅 운영자에게 유효한 사용 사례가 있습니까?
유진 Karataev

1
@EugeneKarataev 예, 프레임 워크는 종종 내부의 변수를 초기화하며 ts 제어 흐름 분석은이를 포착 할 수 없습니다. 사용량이 확실히 줄어들지 만 필요한 인스턴스를 보게 될 것입니다.
arg20
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.