해당 포스트는
러닝 타입스크립트
4장을 읽고 정리한 포스트입니다.
책의 모든 내용을 작성하는 것이 아닌 주관적인 기준에 따라 필요한 정보만 정리했습니다.
🎈 객체 타입
0️⃣ 객체 타입 선언
1
2
3
4
5
6
7
8
9
let myValue: {
name: string;
age: number;
};
myValue = {
name: "Aatrox",
age: 26,
};
1️⃣ 객체 타입 별칭
1
2
3
4
5
6
7
8
9
10
11
type MyValue = {
name: string;
age: number;
};
let myValue: MyValue;
myValue = {
name: "Aatrox",
age: 26,
};
🦆 구조적 타이핑
타입을 충족하면 값이 추가적으로 있어도 사용할 수 있는 것을 의미합니다.
( 조금 더 자세한 예시를 보고 싶다면 여기에서 확인해주세요! )
(1)
과 (2)
처럼 타입과 완벽하게 일치하지 않는 값을 대입해도 문제 없이 동작합니다.
1
2
3
4
5
6
7
8
9
10
11
12
type FirstName = { firstName: string };
type LastName = { lastName: string };
const fullName = {
firstName: "a",
lastName: "b",
};
// (1)
let firstName: FirstName = fullName;
// (2)
let lastName: LastName = fullName;
- 덕 타이핑: 런타임에서 사용될 때까지 객체 타입을 검사하지 않는 것을 의미 (
JavaScript
) - 구조적 타이핑: 정적 시스템이 타입을 검사하는 것을 의미 (
TypeScript
)
0️⃣ 사용 검사
객체 타입에 정의한 값을 필수적으로 선언해야 합니다. ( (1)
)
또한 타입의 정보와도 일치해야 합니다. ( (2)
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Person = {
name: string;
age: number;
};
// (1) Error: Property 'age' is missing in type '{ name: string; }' but required in type 'Person'
const person: Person = {
name: "Aatrox",
};
// (2) Error: Type 'string' is not assignable to type 'number'
const person: Person = {
name: "Aatrox",
age: "10",
};
1️⃣ 초과 속성 검사
정해진 타입보다 더 많은 속성을 부여하면 타입 오류가 발생합니다. ( (3)
)
하지만 객체 리터럴이 아닌 경우에는 구조적 타이핑에 의해서 오류가 발생하지 않습니다. ( (4)
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
type Person = {
name: string;
age: number;
};
// (3)
const person1: Person = {
name: "Aatrox",
age: 10,
// Error: Type '{ name: string; age: number; gender: boolean; }' is not assignable to type 'Person'.
// Error: Object literal may only specify known properties, and 'gender' does not exist in type 'Person
gender: true,
};
// (4)
const person = {
name: "Aatrox",
age: 26,
gender: true,
};
// (4)
const person2: Person = person;
// Error: Property 'gender' does not exist on type 'Person'.
person2.gender;
2️⃣ 중첩된 객체 타입
객체의 속성으로 타입을 사용할 수 있기 때문에 (5)
처럼 사용하는 것보다는 (6)
처럼 사용하는 것이 더 좋습니다.
가독성도 더 좋고, 오류 메시지도 더 명확해집니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type Vision = {
left: number;
right: number;
};
// (5)
type Person1 = {
name: string;
age: number;
vision: {
left: number;
right: number;
};
};
// (6)
type Person2 = {
name: string;
age: number;
vision: Vision;
};
3️⃣ 선택적 속성
?:
을 이용해서 선택적 속성을 부여할 수 있습니다.
선택적 속성은 존재하지 않아도 되고 undefined
를 넣어줘도 됩니다. ( (7)
)
하지만 undefined
를 유니언으로 선언했다면 속성 값을 반드시 선언해줘야합니다. ( (8)
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
type Person = {
name: string;
age?: number;
gender: boolean | undefined;
};
/**
* type Person = {
* name: string;
* age?: number | undefined;
* gender: boolean | undefined;
* }
*/
// (7)
const person1: Person = {
name: "Aatrox",
age: 26,
gender: false,
};
// (8) Error: Property 'gender' is missing in type '{ name: string; age: number; }' but required in type 'Person'
const person2: Person = {
name: "Aatrox",
age: 26,
};
// (7) 문제 없음
const person3: Person = {
name: "Aatrox",
gender: false,
};
// (8) "undefined"라도 반드시 선언해줘야 함
const person4: Person = {
name: "Aatrox",
age: 26,
gender: undefined;
};
🌌 객체 타입 유니온
0️⃣ 유추된 객체 타입 유니온
여러 가지 객체가 될 수 있는 초깃값을 할당하면 객체들의 유니온 타입으로 추론합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const person =
Math.random() > 0.5 ? { name: "AA", age: 2 } : { name: "BB", gender: true };
/**
* const person: {
* name: string;
* age: number;
* gender?: undefined;
* } | {
* name: string;
* gender: boolean;
* age?: undefined;
* }
*/
person.name;
person.gender;
person.age;
1️⃣ 명시된 객체 타입 유니온과 객체 타입 내로잉
값의 타입이 객체 타입인 유니온이라면 일반적으로는 모든 유니온에 존재하는 값만 사용할 수 있습니다. ((1)
)
하지만 타입 내로잉을 사용하면 특정 객체 타입으로 좁혀서 정확하게 타입을 추론하고 사용할 수 있습니다.((2)
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
type Person1 = {
name: string;
age: number;
};
type Person2 = {
name: string;
gender: boolean;
};
let person: Person1 | Person2;
person =
Math.random() > 0.5 ? { name: "AA", age: 2 } : { name: "BB", gender: true };
// (1)
person.name;
// Error: Property 'age' does not exist on type 'Person1 | Person2'.
person.age;
// Error: Property 'gender' does not exist on type 'Person1 | Person2'.
person.gender;
// (2)
if ("age" in person) {
person.age;
} else {
person.gender;
}
2️⃣ 판별된 유니온
판별된 유니온이란 각 객체마다 각자의 태그를 붙여서 해당 태그로 타입을 구분할 수 있도록 판별하는 것을 의미합니다.
판별된 유니온을 이용해서 타입 내로잉을 하는 것이 좋습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type Person1 = {
type: "person1";
name: string;
age: number;
};
type Person2 = {
type: "person2";
name: string;
gender: boolean;
};
let person: Person1 | Person2;
person =
Math.random() > 0.5
? { type: "person1", name: "AA", age: 2 }
: { type: "person2", name: "BB", gender: true };
if (person.type === "person1") {
person.age;
} else {
person.gender;
}
🏁 교차 타입
인터섹션(&
)을 이용하고 각 타입에 선언된 모든 속성의 합집합인 타입이 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Person1 = {
name: string;
age: number;
};
type Person2 = {
name: string;
gender: boolean;
};
declare const person: Person1 & Person2;
person.name;
person.age;
person.gender;
교차 타입과 판별된 유니온을 같이 사용하면 아래와 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type Person1 = {
age: number;
type: "person1"
};
type Person2 = {
gender: boolean;
type: "person2"
};
declare const person: { name: string } & ( Person1 | Person2 );
// "name: string"을 가지면서 "Person1"인 경우
if(person.type === "person1") {
person.age;
person.name;
}
// "name: string"을 가지면서 "Person2"인 경우
else {
person.name;
person.gender;
}
0️⃣ 교차 타입의 위험성
교차 타입을 잘못 사용하면 불가능한 타입인 never
가 생성될 위험이 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
// type MyType = never
type MyType = number & string;
type T1 = {
name: string;
};
type T2 = {
name: number;
};
// T: { name: never }
type T = T1 & T2;
📮 레퍼런스
« 러닝 타입스크립트 4장 » ( 조시 골드버그 지음, 고승원 옮김, 한빛미디어, 2023 )
- 1-blue - 판별된 유니온
- 1-blue - 구조적 타이핑