Skip to content

Commit

Permalink
Create 15-1.md (#170)
Browse files Browse the repository at this point in the history
  • Loading branch information
newminkyung authored Jun 29, 2024
1 parent 896ee6e commit 8286b64
Showing 1 changed file with 125 additions and 0 deletions.
125 changes: 125 additions & 0 deletions new/15-1.md
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` 함수의 콜백에는 패턴에 맞는 데이터가 타입 추론이 된 채로 넘어오기 때문

0 comments on commit 8286b64

Please sign in to comment.