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;

이 경우, 당신은 x과 y같은 유형이,하지만 사용하려고하면 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.