-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #50 from Orchemi/master
#47 Post. Advanced TypeScript
- Loading branch information
Showing
1 changed file
with
347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,347 @@ | ||
# TypeScript 고급 | ||
|
||
<!-- 발표 영상: https://www.youtube.com/watch?v=wmTkIlY9lXU --> | ||
|
||
## 제네릭(Generics) | ||
|
||
### 제네릭이란? | ||
|
||
> 재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징 | ||
**한 가지 타입보다 여러 가지 타입에서 동작하는 컴포넌트 생성에 사용** | ||
|
||
<br> | ||
|
||
```js | ||
// JavaScript | ||
function logText(text) { | ||
console.log(text); | ||
return text; | ||
} | ||
|
||
logText('Hello'); | ||
logText(10); | ||
logText(true); | ||
``` | ||
|
||
- JS 문법의 경우 위와 같은 함수에서는 어떤 것이든 인자로 사용 가능 | ||
|
||
<br> | ||
|
||
```ts | ||
// TypeScript | ||
function logText<T>(text: T): T { | ||
console.log(text); | ||
return text; | ||
} | ||
|
||
logText<string>('Hello'); | ||
``` | ||
|
||
- TS의 generic을 활용하면 **함수를 호출할 때 type을 정의하겠다**는 약속 | ||
- 함수를 추상화해서 더 다양한 type에서 사용 가능 | ||
|
||
<br> | ||
|
||
![image](https://user-images.githubusercontent.com/86189596/173964717-a4c8de60-89e0-4b87-86ec-4c0109d70768.png) | ||
|
||
- 함수 호출에서 type을 정의하면 해당하는 type의 전달과 출력이 type으로 지정 | ||
|
||
<br> | ||
|
||
### 기존 TS 함수의 중복 선언 | ||
|
||
```js | ||
function logText(text: string) { | ||
console.log(text); | ||
return text; | ||
} | ||
|
||
function logNumber(num: number) { | ||
console.log(num); | ||
return num; | ||
} | ||
|
||
logText('a') | ||
logNumber(10) | ||
``` | ||
|
||
- 기존 TS 문법은 type에 따라 함수를 중복 정의 해야한다. | ||
- 유지보수 차원에서 좋지 않음 | ||
|
||
<br> | ||
|
||
### 유니온 타입을 이용한 선언 방식 문제점 | ||
|
||
```ts | ||
function logText(text: string | number) { | ||
console.log(text); | ||
return text; | ||
} | ||
``` | ||
|
||
> 문제점1. 지정된 여러 type이 공통으로 가지는 method에서만 preview 지원 | ||
![image](https://user-images.githubusercontent.com/86189596/173974315-b5d3e702-f8a2-4973-9cb6-a3deecd59a2f.png) | ||
|
||
<br> | ||
|
||
> 문제점2. 한 가지 타입에서만 존재하는 메서드 사용 불가 | ||
![image](https://user-images.githubusercontent.com/86189596/173974478-986beeef-1030-488e-9c90-277e99a356d1.png) | ||
|
||
- 해당 함수의 결과값은 union type이므로 한 가지 type에서만 지원하는 메서드 사용 불가 | ||
|
||
<br> | ||
|
||
### 제네릭의 장점과 타입 추론에서의 이점 | ||
|
||
```ts | ||
function logText<T>(text: T): T { | ||
console.log(text); | ||
return text; | ||
} | ||
|
||
const str = logText<string>('a') | ||
str.split('') | ||
|
||
const num = logText<number>(10) | ||
num.toLocaleString() | ||
``` | ||
|
||
- generic을 통한 type 정의를 통해 return된 값을 변수로 지정 | ||
- 이 변수는 각 type에서 지원하는 method 사용 가능 | ||
|
||
![image](https://user-images.githubusercontent.com/86189596/174127271-80278ded-b588-43da-9279-1f610984da11.png) | ||
|
||
<br> | ||
|
||
### 인터페이스에 제네릭 선언 | ||
|
||
```ts | ||
interface Dropdown<T> { | ||
value: T; | ||
selected: boolean; | ||
} | ||
|
||
const obj1: Dropdown<string> = { value: 'abc', selected: false }; | ||
const obj2: Dropdown<number> = { value: 10, selected: false }; | ||
``` | ||
|
||
<br> | ||
|
||
### 제네릭의 타입 제한 | ||
|
||
```ts | ||
function logTextLength<T>(text: T): T { | ||
console.log(text.length); | ||
return text; | ||
} | ||
|
||
logTextLength('hi'); | ||
``` | ||
|
||
- 함수 내부에서 인자의 메서드 사용은 인자의 type마다 다르다. | ||
- generic에서 type은 호출 때 정의되므로, 함수 작성 시에는 오류 발생 | ||
|
||
![image](https://user-images.githubusercontent.com/86189596/174138959-ca4af74a-ed1e-423a-a748-374fb2e61ac4.png) | ||
|
||
<br> | ||
|
||
> 힌트를 주자! | ||
- text는 length를 셀 수 있는 애라는 것을 알린다! | ||
- text는 배열이라고 가정 | ||
|
||
```ts | ||
function logTextLength<T>(text: T[]): T[] { | ||
console.log(text.length); | ||
text.forEach(function (text) { | ||
console.log(text); | ||
}) | ||
return text; | ||
} | ||
|
||
logTextLength<string>(['hi', 'abc']); | ||
``` | ||
|
||
- 실제 인자도 Array 형태로 전달해야 한다. | ||
|
||
<br> | ||
|
||
### 제네릭의 타입 제한2 : 정의된 타입 이용 | ||
|
||
```ts | ||
interface LengthType { | ||
length: number; | ||
} | ||
|
||
function logTextLength<T extends LengthType>(text: T): T { | ||
text.length; | ||
return text; | ||
} | ||
|
||
logTextLength('abcdef'); | ||
logTextLength(['a', 'b', 'c', 'd']) | ||
logTextLength({ length: 10 }) | ||
logTextLength(10); | ||
``` | ||
|
||
- 정의될 Type은 length 속성/메서드를 가진 LengthType의 상속을 받는 type이 된다. | ||
- T type은 LengthType에 추가로 정의 | ||
|
||
![image](https://user-images.githubusercontent.com/86189596/174140574-08be9372-f30c-4fd0-9803-624eca70aeb1.png) | ||
|
||
<br> | ||
|
||
### 제네릭의 타입 제한3 : keyof 이용 | ||
|
||
```ts | ||
interface ShoppingItem { | ||
name: string; | ||
price: number; | ||
stock: number; | ||
} | ||
|
||
function getShoppingItemOption<T extends keyof ShoppingItem>(itemOption: T): T { | ||
return itemOption; | ||
} | ||
getShoppingItemOption('name'); | ||
``` | ||
|
||
interface의 key들 중 하나를 인자로 사용 | ||
|
||
<br> | ||
|
||
## Promise를 이용한 API 함수 타입 정의 | ||
|
||
```ts | ||
function fetchItems(): Promise<string[]> { | ||
let items = ['a', 'b', 'c']; | ||
return new Promise(function (resolve) { | ||
resolve(items); | ||
}) | ||
} | ||
fetchItems(); | ||
``` | ||
|
||
<br> | ||
|
||
## enum을 이용한 타입 정의 | ||
|
||
```ts | ||
findContactByPhone(phoneNumber: number, phoneType: string): Contact[] { | ||
return this.contacts.filter( | ||
contact => contact.phones[phoneType].num === phoneNumber | ||
); | ||
} | ||
``` | ||
|
||
<br> | ||
|
||
|
||
이런 함수의 경우 인자로 phoneType을 받는다. | ||
|
||
```ts | ||
findContactByPhone('Homee'); | ||
``` | ||
|
||
그런데 이런 경우 오타를 방지할 수 없기 때문에 아래와 같이 enum을 사용 | ||
|
||
<br> | ||
|
||
```ts | ||
enum PhoneType { | ||
Home = 'home', | ||
Office = 'office', | ||
Studio = 'studio', | ||
} | ||
``` | ||
|
||
```ts | ||
findContactByPhone(PhoneType.Home); | ||
``` | ||
|
||
오타에 대한 에러를 바로 확인 가능 | ||
|
||
<br> | ||
|
||
## 타입 추론(Type Inference) | ||
|
||
### 타입 추론이란? | ||
|
||
```ts | ||
// parameter의 type으로 return 값의 type이 결정 | ||
function getB(b) { | ||
return b; | ||
} | ||
``` | ||
|
||
```ts | ||
// parameter의 type으로 return 값의 type이 결정 | ||
function getB(b) { | ||
const c = 'hi' | ||
return b + c; | ||
} | ||
``` | ||
|
||
- number + string = string으로 type 추론 | ||
- return 값이 내부적으로 string으로 추론 | ||
|
||
<br> | ||
|
||
### 인터페이스와 제네릭에서의 타입 추론 | ||
|
||
> 인터페이스와 제네릭 | ||
```ts | ||
interface Dropdown<T> { | ||
value: T; | ||
title: string; | ||
} | ||
|
||
const shoppingItem: Dropdown<string> = { | ||
value: 'abc', | ||
title: 'hello', | ||
} | ||
``` | ||
|
||
<br> | ||
|
||
> 인터페이스의 상속 | ||
```ts | ||
interface Dropdown<T> { | ||
value: T; | ||
title: string; | ||
} | ||
|
||
// 관행적으로 T를 쓰지만 구분을 위해 K 사용 | ||
interface DetailedDropdown<K> extends Dropdown<K> { | ||
description: string | ||
tag: K; | ||
} | ||
|
||
const detailedItem: DetailedDropdown<string> = { | ||
value: 'abc', | ||
title: 'hello', | ||
description: '안녕하세요~~', | ||
tag: 'a' | ||
} | ||
``` | ||
|
||
인터페이스 A를 상속받은 인터페이스 B는 generic의 Type도 상속 가능 | ||
|
||
<br> | ||
|
||
### Best Common Type | ||
|
||
> 배열 내에 type이 여러 종류가 있는 경우 | ||
```ts | ||
const arr: (number | string | boolean)[] = [1, 2, 3, 'a', 'b', 'c', true]; | ||
``` | ||
|
||
유니온 타입을 이용해 배열에 들어간 개체들의 타입을 추론해 union type으로 정의 | ||
|
||
![image](https://user-images.githubusercontent.com/86189596/174268126-33d74c33-0a86-45fc-919e-3d08201a55fc.png) |