Item 8 타입 공간과 값 공간의 심벌 구분하기
Symbols
타입스크립트의 심벌(symbol)은 타입 공간이나 값 공간 중의 한 곳에 존재한다.
interface Cylinder {
radius: number
height: number
}
const Cylinder = (radius: number, height: number) => ({ radius, height })
function calculateVolume(shape: unknown) {
if (shape instanceof Cylinder) {
shape.radius
// ~~~~~~~ Property 'radius' does not exist on type '{}'.
}
}
이 둘을 구분할 수 있을까? 이름은 같지만 하나는 타입이고 하나는 값으로 쓰이며, 서로 관련이 없다. 이런 점이 가끔 문제를 야기하므로 문맥을 읽어야 한다.
리터럴 예시
// 심벌이 '타입'이다
type T1 = 'string literal'
type T2 = 123
// 심벌이 '값'이다
const v1 = 'string literal'
const v2 = 123
대입(=) 예시
TS 코드에서 타입과 값은 번갈아 나올 수 있다. 타입 선언(:
) 또는 단언문(as
) 다음에 나오는 심벌은 타입인 반면, =
다음에 나오는 모든 것은 값이다.
interface Person {
first: string
last: string
}
const p: Person = { first: 'Jane', last: 'Jacobs' }
// p, { first: 'Jane', last: 'Jacobs' }는 값이고, Person은 타입이다.
함수 예시
타입과 값이 반복적으로 번갈아 나올 수 있다.
function email(p: Person, subject: string, body: string): Response {
// email, p, subject, body는 값
// Person, string, Response는 타입
// ...
}
클래스 예시
한편, 클래스는 값으로도 타입으로도 쓰일 수 있다.
class Cylinder {
radius = 1
height = 1
}
function calculateVolume(shape: unknown) {
if (shape instanceof Cylinder) {
shape // OK, 타입은 Cylinder
shape.radius // OK, 타입은 number
}
}
클래스가 타입으로 쓰일 때는 형태(속성과 메서드)가 사용된다. (
cylinder: Cylinder
, ...)클래스가 값으로 쓰일 때는 생성자가 사용된다. (
new Cylinder(...)
)
따라서 클래스는 상황에 따라 다르게 동작한다.
const v = typeof Cylinder // 값이 'function'
type t = typeof Cylinder // 타입이 typeof Cylinder
2번째 줄의 경우 t
의 타입이 typeof Cylinder
인데, 중요한 건 Cylinder
가 인스턴스의 타입이 아니라는 것이다.
실제로 new
키워드를 사용할 때 볼 수 있는 생성자 함수이다.
declare let fn: T
const c = new fn() // 타입이 Cylinder
InstanceType
제너릭을 이용해 생성자 타입과 인스턴스 타입을 전환할 수 있다.
type c = InstanceType<typeof Cylinder> // 타입이 Cylinder
typeof
연산자 예시
typeof
연산자 예시타입으로 쓰일 때와 값에서 쓰일 때 다른 기능을 하는 것들 중에는 typeof
연산자가 있다.
type T1 = typeof p // 타입은 Person
type T2 = typeof email // 타입은 (p: Person, subject: string, body: string) => Response
const v1 = typeof p // 값은 'object'
const v2 = typeof email // 값은 'function'
타입의 관점에서
typeof
는 값을 읽어 타입스크립트 타입을 반환한다. (TypeScript Docs)타입 공간의
typeof
는 보다 큰 타입의 일부분으로 사용하거나type
구문으로 이름을 붙일 수 있다.
값의 관점에서
typeof
는 자바스크립트 런타임의typeof
연산자가 된다. (MDN Docs)
속성 접근자 []
예시
[]
예시속성 접근자인 []
는 타입으로 쓰일 때에도 동일하게 동작한다. 하지만 obj['field']
와 obj.field
는 값이 동일하더라도 타입은 다를 수 있다.
따라서 타입의 속성을 얻을 때에는 반드시 첫 번째 방법(obj['field']
)을 사용해야 한다.
const first: Person['first'] = p['first'] // 또는 p.first
// first, p['first']는 값
// Person['first']는 타입
Person['first']
는 여기서 타입 맥락(:
뒤에)에 쓰였기 때문에 타입이다.
type PersonEl = Person['first' | 'last'] // 타입은 string
type Tuple = [string, number, Date]
type TupleEl = Tuple[number] // 타입은 string | number | Date
인덱스 위치에는 유니온 타입과 기본형 타입을 포함한 어떠한 타입이든 사용할 수 있다.
속성 접근자에 대한 내용은 Item 14에서 더 자세히 다룬다.
그 외 타입 공간과 값 공간 사이에서 다른 의미를 가지는 코드 패턴들
this
JS의 this
키워드 (Item 49)
다형성(polymorphic) this
라고 불리는 TS 타입이다. 서브클래스의 메서드 체인을 구현할 때 유용하다.
&
, |
AND와 OR 비트연산
인터섹션과 유니온
const
const
는 새 변수를 선언한다.
as const
는 리터럴 또는 리터럴 표현식의 추론된 타입을 바꾼다.(Item 21)
extends
서브클래스(class A extends B
)
서브타입(
interface A extends B
)
제너릭 타입의 한정자(
Generic<T extends number>
)를 정의한다.
in
루프 (for (key in object)
)
매핑된(mapped) 타입에 등장
Last updated
Was this helpful?