-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
896ee6e
commit 8286b64
Showing
1 changed file
with
125 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,125 @@ | ||
## 타입스크립트 패턴 매칭 | ||
|
||
### 패턴매칭 | ||
> - 특정 패턴에 맞는 데이터를 찾거나 추출하는 기능은 많은 함수형 프로그래밍 언어에서 사용되는 개념 | ||
> - Haskell, OCaml, Erlang, Rust, Swift, Elixir, Rescript 등 많은 언어에서 이 기능을 지원 | ||
- 함수형 프로그래밍은 데이터를 조작하고 처리하기 위해 선언적인 방식을 채택 | ||
- 패턴 매칭이라는 메커니즘을 사용하여 특정 패턴을 가진 데이터를 찾거나 추출 | ||
- 패턴 매칭을 사용하여 리스트에서 특정 요소를 찾거나 | ||
- 특정 데이터 구조에서 원하는 값을 추출하는 등 | ||
|
||
#### Rust에서 패턴매칭 | ||
- `match` 키워드를 사용 | ||
|
||
``` rust | ||
fn main() { | ||
let p = Point { x: 0, y: 7 }; | ||
|
||
match p { | ||
Point { x, y: 0 } => println!("x값은 x축 위에 있습니다. 값: {}", x), | ||
Point { x: 0, y } => println!("y값은 y축 위에 있습니다. {}", y), | ||
Point { x, y } => println!("좌표값: ({}, {})", x, y), | ||
} | ||
} | ||
``` | ||
|
||
- `Point` 구조체의 인스턴스 `p`를 여러 패턴으로 매칭시켜 해당 패턴에 따라 결과를 출력 | ||
|
||
#### 패턴매칭 vs 조건문 | ||
> 주어진 조건 또는 패턴에 따라 동작을 분기시킨다는 역할이 동일하다 | ||
> 하지만 이 둘은 동작하고 사용되는 상황이 다르다 | ||
- 패턴매칭 | ||
- 데이터의 구조나 패턴을 중심으로 동작 | ||
- 데이터의 패턴 정의 | ||
- 주어진 패턴이나 구조와 비교하여 일치하는 경우에 특정 동작을 수행 | ||
- 주로 문자열, 리스트, 튜플 등과 같은 데이터 구조에서 패턴을 비교하고, 패턴에 맞는 데이터를 추출하거나 처리하는 데 사용 | ||
|
||
- 조건문 | ||
- 주어진 조건에 따라 프로그램의 흐름을 분기 | ||
- 주어진 조건이 참인 경우, 특정 코드 블록을 실행 | ||
- 조건이 거짓인 경우, 다른 코드 블록을 실행하거나 흐름을 제어 | ||
|
||
-> 패턴 매칭과 조건문은 목적과 사용 방식에서 차이가 있지만, 두 가지 모두 프로그램의 제어 흐름을 분기시키는 데 사용되는 기능 | ||
|
||
### 자바스크립트에서의 패턴 매칭 | ||
- [TC39](https://github.com/tc39/proposal-pattern-matching)에 1단계까지 진행됨 | ||
- `@babel/plugin-proposal-pattern-matching`, `xstat`, `lodash` 의 `_matchs` 를 사용하면 패턴매칭을 자바스크립트에서도 구현할 수 있음 | ||
|
||
### ts-pattern | ||
- 타입스크립트에서 패턴 매칭을 구현할 수 있게 해주는 라이브러리 | ||
|
||
#### 예시 | ||
``` ts | ||
import { match } from 'ts-pattern'; | ||
|
||
type Weather = '맑음' | '구름' | '비' | '눈'; | ||
|
||
const getWeatherDescription = (weather: Weather): string => { | ||
return match<Weather, string>(weather) | ||
.with('맑음', () => '오늘은 맑은 날이네요! 선크림을 꼭 챙기세요.🕶️') | ||
.with('구름', () => '오늘은 구름이 낀 날이에요.🌥️') | ||
.with('비', () => '오늘은 비가 오네요! 꼭 우산을 챙기세요.🌧️') | ||
.with('눈', () => '오늘은 눈이 오네요! 눈사람 만들 준비가 되셨나요?☃️') | ||
.exhaustive(() => '유효하지 않은 날씨입니다.'); | ||
}; | ||
|
||
const currentWeather = 'sunny'; | ||
const weatherDescription = getWeatherDescription(currentWeather); | ||
console.log(weatherDescription); // 오늘은 맑은 날이네요! 선크림을 꼭 챙기세요.🕶️ | ||
``` | ||
|
||
- 주어진 weather 값에 따라 해당하는 날씨 설명을 반환 | ||
- `match` 함수를 사용하여 `weather` 값과 매칭되는 내용을 선택 | ||
|
||
#### 또 다른 예시 | ||
|
||
- 기존 코드의 문제 | ||
``` ts | ||
declare let fetchState: | ||
| { status: { label: "loading" }} | ||
| { status: { label: "success" }, data: string } | ||
| { status: { label: "error" }, message: string }; | ||
|
||
// switch 사용 | ||
switch (fetchState.status.label) { | ||
case "loading": | ||
console.log("로딩중.."); | ||
break; | ||
case "success": | ||
console.log("성공! 데이터: ", fetchState.data); //type error! | ||
break; | ||
case "error": | ||
console.error("에러: ", fetchState.message); //type error! | ||
break; | ||
} | ||
|
||
// if 사용 | ||
if (fetchState.status.label === "loading") { | ||
console.log("로딩중.."); | ||
} else if (fetchState.status.label === "success") { | ||
console.log("성공! 데이터: ", fetchState.data); //type error! | ||
} else if (fetchState.status.label === "error") { | ||
console.error("에러: ", fetchState.message); //type error! | ||
} | ||
``` | ||
|
||
- `if-else`로 조건문을 사용한 경우에는 타입 변경에 매우 취약 | ||
- fetchState의 타입에 또 다른 상태(ex. { label: "idle" })가 추가되더라도, 코드에서 어떤 상태에 따라 분기하는 부분에서 에러가 발생하지 않음 | ||
|
||
- ts-pattern을 이용하면 | ||
|
||
``` ts | ||
match(fetchState) | ||
.with({ status: { label: "loading" } }, () => console.log("로딩중..")) | ||
.with({ status: { label: "success" } }, ({ data }) => | ||
console.log("성공! 데이터: ", data) | ||
) | ||
.with({ status: { label: "error" } }, ({ message }) => | ||
console.error("에러: ", message) | ||
) | ||
.exhaustive(); | ||
``` | ||
- 타입 추론을 자연스럽게 할 수 있음 | ||
- `with` 함수의 콜백에는 패턴에 맞는 데이터가 타입 추론이 된 채로 넘어오기 때문 |