You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
즉, 타입스크립트 컴파일러는 `string& {}`를 <u>더 구체적인 타입으로 간주</u>하여 문자열 리터럴(`"foo", "bar"`)과 `string& {}`를 `string`으로 합치지 않고 구분하여 유니온 타입으로 표현하게 된다.
64
+
`string & {}`이 <u>구체적인 타입</u>인 `string`으로 좁혀지지 않았기 때문에 타입스크립트 컴파일러는 해당 타입을 문자열 리터럴과 다른 타입으로 간주하게 된다.
57
65
58
66
이러한 특성 때문에 우리는 문자열 리터럴을 사용하면서 문자열을 확장할 수 있게 된다.
59
67
60
68
> 관련 내용은 타입스크립트 이슈([Literal String Union Autocomplete #29729](https://github.com/microsoft/TypeScript/issues/29729#issuecomment-567871939))에서 확인할 수 있다.
61
69
62
-
63
70
### 구체적인 타입
64
71
65
-
타입스크립트에서는 타입을 "구체적으로 나타내는" 방식이 있다. 이는 타입스크립트의 타입 시스템이 [구조적 서브 타이핑](/posts/typescript-subtyping#%EA%B5%AC%EC%A1%B0%EC%A0%81-%EC%84%9C%EB%B8%8C-%ED%83%80%EC%9D%B4%ED%95%91%EC%9D%B4%EB%9E%80)을 따르기 때문이다.
72
+
타입스크립트의 타입 시스템은[구조적 서브 타이핑](/posts/typescript-subtyping#%EA%B5%AC%EC%A1%B0%EC%A0%81-%EC%84%9C%EB%B8%8C-%ED%83%80%EC%9D%B4%ED%95%91%EC%9D%B4%EB%9E%80)을 따른다. 그렇기에 각 타입을 구조적으로 비교한다.
66
73
67
-
타입스크립트는 타입을 구조적으로 비교한다. 이때 교집합(`&`)을 사용하면 더 구체적인 타입으로 간주하게 된다.
74
+
이때 교집합(`&`)을 사용하면 더 구체적인 타입으로 나타낼 수 있다.
68
75
69
76
```ts
70
77
typeA= { a:string };
71
78
typeB= { a:'A'|'B'; b:number };
72
-
typeC=A&B; // { a: 'A' | 'B', b: number };
79
+
typeANB=A&B; // { a: 'A' | 'B', b: number };
80
+
```
81
+
82
+
구조적 서브 타이핑에 익숙하지 않으면 위의 예에서 "중첩"만 생각해 중첩되는 `'a'` 프로퍼티만 가져와 `A & B = { a: 'A' | 'B' }`로 생각할 수 있다. 하지만 <u>`A & B`의 의미는 `A`와 `B` 타입 모두를 만족하는 타입</u><ExternalAnchorhref="https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#intersection-types" />을 의미한다.
83
+
84
+
집합적 관점에서 생각해보자. `x ∈ A ∩ B`일 필요충분조건은 `x ∈ A` 혹은 `x ∈ B` 이다<ExternalAnchorhref="https://ko.wikipedia.org/wiki/%EA%B5%90%EC%A7%91%ED%95%A9" />.
85
+
86
+
> \{★, ●}, \{★, ●, ◆}의 교집합은 \{★, ●}이다. 교집합은 부모와 같아질 수 있다.
87
+
88
+
```ts
89
+
typeTest1=ANBextendsA?true:false; // true
90
+
typeTest2=ANBextendsB?true:false; // true
73
91
```
74
92
75
-
구조적 서브 타이핑에 익숙하지 않으면 위의 예에서 "교집합"만 생각해 중첩되는 `'a'` 프로퍼티만 가져와 `A & B = { a: 'A' | 'B' }`로 생각할 수 있다. 하지만 <u>`A & B`의 의미는 `A`와 `B`의 모든 프로퍼티를 만족하는 타입</u>을 의미한다.
93
+
그렇다면 위의 논리로 `ANB`를 살펴보자. `ANB`는 `A`와 `B`의 구체적인 타입(교집합)이므로 `ANB`는 `A` 혹은 `B`로 간주될 수 있어야 한다.
76
94
77
-
모든 타입, 프로퍼티를 만족한다는 것은 결국 가장 구체적인(작은) 타입을 만족한다는 것이다.
95
+
`A & B` 타입이 `A` 타입이 되려면 `{ a: string }`을 만족해야 하며 `B` 타입이 되기 위해선 `{ a: 'A' | 'B', b: number }`를 만족해야 한다.
78
96
79
-
따라서 `A`타입의 `'a'` 프로퍼티(`string`)와 `B`타입의 `'a'` 프로퍼티(`'A' | 'B'`)를 만족하는 구체적인 타입인 문자열 리터럴 타입(`'A' | 'B'`)과 `B` 타입의 `'b'` 프로퍼티(`number`)를 가져오는 것이다.
97
+
이를 구조적으로 표현하기 위해서 `A & B`는 `A`와 `B`의 모든 속성을 가져오고 속성이 겹친다면 가장 좁은 타입을 적용하게 된다.
80
98
81
-
아래 예제를 보면 명확해진다.
99
+
> \{ a: string, b: number } 타입은 A는 만족하지만 B는 만족하지 않기 때문.
100
+
101
+
아래 예제를 보면 더 명확해진다.
82
102
83
103
```ts
84
-
const a = { a: 'A' };
85
-
const aa = { a: 'A', b: 1 };
104
+
typeA= { a:string };
105
+
typeB= { a:'A'|'B'; b:number };
106
+
typeANB=A&B; // { a: 'A' | 'B', b: number };
107
+
108
+
const a = { a: 'Astring' };
109
+
const aa = { a: 'Astring', b: 1 };
86
110
// 타입 B의 a 프로퍼티가 'A' | 'B' 타입이므로 더 좁은 타입으로 강제 지정해줘야 함.
87
111
const b = { a: 'B'as'A'|'B', b: 2 };
88
112
const bb = { a: 'B'as'A'|'B', b: 2, c: 'ddd' };
89
113
90
114
const goA = (param:A) =>console.log(param);
91
115
const goB = (param:B) =>console.log(param);
92
-
constgoC= (param:C) =>console.log(param);
116
+
constgoANB= (param:ANB) =>console.log(param);
93
117
94
118
goA(a); // OK
95
119
goA(aa); // OK. 타입에 없는 b 프로퍼티가 추가되어도 a가 있으므로 "구조적으로" 상관없음.
96
120
97
121
goB(b); // OK
98
122
goB(bb); // OK
99
123
100
-
goC(a); // Error. b 프로퍼티가 없음.
101
-
goC(aa); // Error. a 프로퍼티의 타입이 구조적으로 맞지 않음(넓음).
102
-
goC(b); // OK
103
-
goC(bb); // OK. c 프로퍼티가 추가되어도 a, b가 있으므로 "구조적으로" 상관없음.
124
+
goANB(a); // Error. b 프로퍼티가 없음.
125
+
goANB(aa); // Error. a 프로퍼티의 타입이 구조적으로 맞지 않음(넓음).
126
+
goANB(b); // OK
127
+
goANB(bb); // OK. c 프로퍼티가 추가되어도 a, b가 있으므로 "구조적으로" 상관없음.
104
128
```
105
129
106
-
구조적 서브 타이핑의 논리에 따라 `string & {}`는 `string`을 의미하여도 `string`보다 더 구체적인 "타입"으로 정의된다.
130
+
요구하는 타입의 구조만 만족한다면 그 외의 속성이 있어도 타입 에러가 발생하지 않는 것을 확인할 수 있다.
107
131
108
-
이는 `string`과는 다른 타입이므로 문자열 리터럴과 유니온 타입을 지정할 때 `string`으로 잡아먹히지 않게 된다.
`object` 타입은 [원시 타입이 아닌 모든 값을 나타낸다](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#object-type).
207
242
243
+
> object 타입은 타입스크립트 2.2 버전에서 추가되었다.
244
+
208
245
위에서 살펴본 자바스크립트의 타입을 기준으로 보면 원시 타입이 아닌 모든 값은 곧 객체 타입이다. 따라서 `object` 타입은 원시 타입을 제외한 모든 객체 타입을 나타낸다.
209
246
210
247
### \{\} 타입
@@ -225,7 +262,7 @@ const obj7: {} = []; // OK.
225
262
226
263
> 타입스크립트 공식 FAQ - [#Primitives are \{}, and \{} Doesn't Mean object](https://github.com/microsoft/TypeScript/wiki/FAQ#primitives-are---and---doesnt-mean-object).
227
264
>
228
-
> 해당 FAQ를 보면 [원시 타입](/posts/implicit-coercion#%EB%93%A4%EC%96%B4%EA%B0%80%EA%B8%B0-%EC%A0%84%EC%97%90)은 `{}`이며 `{}`는 객체 타입만을 의미하지 않는다고 한다.
265
+
> 해당 FAQ를 보면 [원시 타입](/posts/implicit-coercion#%EB%93%A4%EC%96%B4%EA%B0%80%EA%B8%B0-%EC%A0%84%EC%97%90)은 `{}`이며 `{}`는 object 타입을 의미하지 않는다고 한다.
0 commit comments