value instanceof SomeClass는 런타임에 실행되는 JavaScript 검사입니다. 객체의 프로토타입 체인에 SomeClass.prototype이 있으면, 즉 객체가 new SomeClass(또는 하위 클래스)로 만들어졌으면 true입니다. TypeScript는 검사 안에서 value를 SomeClass로 좁힙니다.
클래스로 만든 객체에는 instanceof를, 원시 타입에는 typeof를 쓰세요. 여기서는 둘 다 필요합니다. instanceof가 Date를 가려내고, typeof가 나머지를 나눕니다.
직접 만든 클래스 좁히기
instanceof는 true 분기에서 해당 클래스로 좁히고 false 분기에서 그 클래스를 없애므로, 클래스들의 유니언을 멤버 하나씩 처리할 수 있습니다.
하위 클래스 인스턴스는 부모에 대한 검사도 통과합니다. Square extends Rect라면 new Square(2) instanceof Rect는 true입니다. 분기마다 처리가 다르다면 가장 구체적인 클래스를 먼저 검사하세요.
catch의 Error 하위 클래스
instanceof가 가장 흔하게 쓰이는 곳은 catch입니다. strict에서 잡힌 값은 unknown이고(무엇이든 던질 수 있으므로), instanceof로 타입이 있는 오류로 돌아갑니다.
출력:
404: /missing.txt
TypeError: path must be absolute
class X extends Error는 TypeScript 7이 지원하는 모든 target(ES2015 이상)에서 instanceof와 함께 동작합니다. 생성자에서 Object.setPrototypeOf(this, X.prototype)을 호출하라는 예전 조언은 ES5로 컴파일한 코드에 해당했고, TypeScript 7은 그 target을 제거했습니다.
instanceof는 인터페이스와 타입에 동작하지 않는다
인터페이스와 타입 별칭은 컴파일러를 위해서만 존재합니다. 컴파일 후에는 비교할 User 값이 없으므로 TypeScript는 검사를 거부합니다.
컴파일러는 index.ts(8,24): error TS2693: 'User' only refers to a type, but is being used as a value here.를 보고합니다. 해결 방법은 두 가지입니다. value is User를 반환하는 함수, 즉 타입 가드로 모양을 직접 확인하세요.
또는 코드에서 이 객체를 직접 만든다면 User를 클래스로 만들고 new로 생성하세요. 그러면 instanceof가 동작합니다. 서술어와 단언 함수는 타입 가드 페이지에서 자세히 다룹니다.
올바른 타입이 올바른 인스턴스는 아니다
TypeScript는 타입을 구조로 비교합니다. 클래스와 멤버가 같은 객체 리터럴은 그 클래스 타입에 대입할 수 있습니다. instanceof는 구조를 보지 않습니다. 프로토타입 체인을 따라가므로, new로 만든 적 없는 객체는 컴파일러가 그 타입으로 받아들이더라도 검사에 실패합니다.
마지막 줄이 중요합니다. structuredClone, JSON.parse(JSON.stringify(...)), 워커 간 메시지는 모두 클래스 프로토타입 없는 평범한 객체를 반환하지만, 정적 타입은 여전히 Point라고 말할 수 있습니다. 클래스 인스턴스가 이런 경계를 넘으면, instanceof나 메서드에 기대기 전에 다시 만드세요(new Point(copy.x, copy.y)).
instanceof와 원시 타입
원시 타입(string, number, boolean...)은 객체가 아니고 프로토타입 체인도 없으므로 "hi" instanceof String은 false입니다. TypeScript는 가능하면 이 실수를 표시합니다. 왼쪽에 string 타입 값이 오면 instanceof는 오류 TS2358, The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.입니다. 원시 타입에는 typeof를 쓰세요.
| 값 | instanceof 검사 | 결과 |
|---|---|---|
new Date() | instanceof Date | true |
[1, 2] | instanceof Array | true(하지만 Array.isArray 권장) |
new TypeError("x") | instanceof Error | true(하위 클래스) |
{ x: 1, y: 2 } | instanceof Point | false(생성된 적 없음) |
Object.create(null) | instanceof Object | false(프로토타입 없음) |
"hi" | instanceof String | false(원시 값) |
다른 realm의 값
instanceof는 특정한 생성자 객체 하나와 비교합니다. 다른 realm(iframe이나 Node의 vm 컨텍스트)에서 실행되는 코드는 자체 Array, Error, Date를 가지므로, 그곳에서 만든 배열은 이곳의 instanceof Array에 실패합니다. 같은 npm 패키지의 복사본 두 개가 node_modules에 들어가도 마찬가지입니다. 복사본마다 자체 클래스가 있어서, 한쪽의 인스턴스는 다른 쪽에 대한 instanceof에 실패합니다. 배열에는 realm을 넘어서도 동작하는 Array.isArray를 쓰세요. 직접 만든 타입이라면 속성을 확인하는 것(타입 가드나 kind 필드)으로 이 문제를 아예 피할 수 있습니다.
자주 묻는 질문
TypeScript에서 객체가 클래스의 인스턴스인지 어떻게 확인하나요?
value instanceof ClassName을 쓰세요. 런타임 검사(평범한 JavaScript)이며, TypeScript는 if 안에서 value를 ClassName으로 좁힙니다. Date, Map, Error 같은 내장 클래스와 직접 만든 클래스 모두에서 동작합니다.
TypeScript에서 인터페이스에 instanceof를 쓸 수 있나요?
아니요. 인터페이스와 타입 별칭은 TypeScript가 JavaScript로 컴파일할 때 지워지므로 런타임에 비교할 대상이 없습니다. 인터페이스 User에 대한 x instanceof User는 오류 TS2693, "'User' only refers to a type, but is being used as a value here."입니다. 대신 타입 가드 함수로 속성을 확인하거나, 객체를 직접 만든다면 User를 클래스로 만드세요.
올바른 타입의 객체인데 instanceof가 false를 반환하는 이유는 무엇인가요?
TypeScript의 타입은 구조적입니다. 객체 리터럴 { x: 1, y: 2 }는 멤버가 같다면 Point 클래스 타입에 대입할 수 있습니다. 하지만 instanceof는 프로토타입 체인을 확인하고, 그 리터럴은 new Point로 만들어진 적이 없으므로 false입니다. JSON, structuredClone, 메시지 채널을 거친 클래스 인스턴스도 평범한 객체로 돌아오므로 마찬가지입니다.
TypeScript에서 커스텀 Error 클래스에 instanceof가 동작하나요?
네, 최신 target이라면 동작합니다. class NotFound extends Error {} 뒤에 err instanceof NotFound는 true입니다. false를 반환하던 예전 문제는 ES5로 컴파일한 출력에만 해당했고, TypeScript 7은 더 이상 ES5 target을 지원하지 않습니다.
"hello" instanceof String이 false인 이유는 무엇인가요?
문자열 리터럴은 객체가 아니라 원시 값이므로 확인할 프로토타입 체인이 없습니다. instanceof String은 new String()으로 만든 래퍼 객체에만 참입니다. TypeScript는 string 타입 값에 대한 instanceof를 거부합니다(TS2358). 원시 타입에는 typeof value === "string"을 쓰세요.