TypeScript의 'instanceof'에서 " 'Foo'는 유형 만 참조하지만 여기서는 값으로 사용되고 있습니다."라는 오류가 표시되는 이유는 무엇입니까?


90

이 코드를 작성했습니다

interface Foo {
    abcdef: number;
}

let x: Foo | string;

if (x instanceof Foo) {
    // ...
}

그러나 TypeScript는 다음과 같은 오류를주었습니다.

'Foo' only refers to a type, but is being used as a value here.

왜 이런 일이 발생합니까? instanceof내 값에 주어진 유형이 있는지 확인할 수 있다고 생각 했지만 TypeScript는 이것을 좋아하지 않는 것 같습니다.


@ 4castle 아래 답변을 참조하십시오. 그렇지 않으면 당신 말이 맞아요 Foo | string.
Daniel Rosenwasser


그리고 Check if variable is a specific interface type in a typescript union (I do n't really want to hammer this)
Cerbrus

@Jenny O'Reilly, 이제 그것은 확실히 가능한 중복의 중복입니다!
marckassay

답변:


100

무슨 일이야

문제는 즉 instanceof자바 스크립트에서 구조체이며, 자바 스크립트, instanceof기대 우측 피연산자한다. 특히 x instanceof FooJavaScript Foo.prototype에서는 .NET Framework의 프로토 타입 체인에 존재 하는지 여부를 확인하기 위해 런타임 검사를 수행합니다 x.

그러나 TypeScript에서 interfaces에는 방출이 없습니다. 즉 , 런타임에 존재 Foo하거나 Foo.prototype존재 하지 않으므로이 코드는 확실히 실패합니다.

TypeScript는 이것이 결코 작동 하지 않을 수 있음을 알려줍니다 . Foo유형일 뿐이며 전혀 값이 아닙니다!

"대신 무엇을 할 수 instanceof있습니까?"

유형 가드 및 사용자 정의 유형 가드를 살펴볼 수 있습니다 .

"하지만 방금에서로 전환 interface 하면 class어떨까요?"

당신은 전환 유혹 할 수있는 interfaceA와 class,하지만 당신은 타이프 라이터의 구조 형식 시스템에서 그 (것은 주로 어디에 실현해야한다 기반 셰이프 ), 주어진 클래스와 같은 모양이있는 객체를 생성 할 수 있습니다 :

class C {
    a: number = 10;
    b: boolean = true;
    c: string = "hello";
}

let x = new C()
let y = {
    a: 10, b: true, c: "hello",
}

// Works!
x = y;
y = x;

이 경우, 당신은 xy같은 유형이,하지만 사용하려고하면 instanceof둘 중 하나에, 당신은 다른 한편으로는 반대의 결과를 얻을 수 있습니다. 그래서 instanceof하지 않습니다 정말 당신이 타이프의 구조 유형을 활용하는 경우 유형에 대해 많이 말한다.


2
나 자신을 위해 그것을 발견하기 위해 나이가 들었을 것입니다!
마태 복음 레이튼

그래서 기본적으로 나는 더 나은 대답에서 아이디어를 얻지 못했습니다. 수업? 당신이 자세히 설명했기 때문입니다. 그러나 당신이 "유혹을 받았을지도 모른다"는 말과 동시에 혼란 스러웠습니다. 그렇다면 타입 가드 문서 에서처럼 수영 속성뿐만 아니라 모든 속성을 비교해야한다면 어떨까요?
HalfWebDev

5
여기서 요점은 instanceof인터페이스가 아닌 클래스와 함께 작동 한다는 것 입니다. 강조 할 필요가 있다고 생각했습니다.
inorganik 19

5

인터페이스로 런타임에 유형 검사를 수행하려면 검사 하려는 인터페이스에 다른 속성 / 기능 이있는 경우 유형 guards를 사용 합니다.

let pet = getSmallPet();

if ((pet as Fish).swim) {
    (pet as Fish).swim();
} else if ((pet as Bird).fly) {
    (pet as Bird).fly();
}

오리에 대해 배우고 내 Bird 인터페이스에 swim () 함수를 추가하면 어떻게됩니까? 유형 가드에서 모든 애완 동물이 물고기로 분류되지 않습니까? 그리고 각각 세 가지 기능을 가진 세 개의 인터페이스가 있고 두 개가 다른 인터페이스 중 하나와 겹치는 경우?
Kayz

1
@Kayz 인터페이스를 고유하게 식별하는 속성 / 기능이 없으면 실제로 구분할 수 없습니다. 실제로 펫이 될 수있는 펫은 Duck가드가 Fish되지만 호출 할 때 런타임 예외는 없습니다 swim(). 하나의 공통 인터페이스 (예 :)를 만들고 거기로 함수를 Swimmable이동 swim()한 다음 가드를 입력하는 것이 좋습니다 ((pet as Swimmable).swim.
Lee Chee Kiam

형변환을 방지하기 위해 'swim' in pet조건 을 사용할 수 있습니다 . 그것은 것으로이 부분 집합으로 범위를 좁힐 것 swim: 정의 (예 Fish | Mammal)
Akxe

2

Daniel Rosenwasser가 옳고 멋질 수도 있지만 그의 대답을 수정하고 싶습니다. x의 인스턴스를 완전히 확인할 수 있습니다. 코드 조각을 참조하십시오.

그러나 x = y를 할당하는 것도 똑같이 쉽습니다. 이제 y는 C의 모양 만 가졌으므로 x는 C의 인스턴스가 아닙니다.

class C {
a: number = 10;
b: boolean = true;
c: string = "hello";
}

let x = new C()
let y = {
    a: 10, b: true, c: "hello",
}

console.log('x is C? ' + (x instanceof C)) // return true
console.log('y is C? ' + (y instanceof C)) // return false

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