[TS] 대수자료구조에서(ADT) 에서 태그유니언을 사용하기
값의 유무를 명시적으로 다루기위해, 타입스크립트와 같은 *정적인 타입 언어에서는 값의 유무를 명확하게 다루는것이 중요합니다. 이는 데이터가 갑자기 undifined | null 과 같은경우에도 타입추론이 가능해야하며 값을 명시적으로 표기하여야하는 타입스크립트의 정적인 타입언어의 특성을 따르기도 합니다.
export type Some<A> = {
_tag: "Some";
value: A;
};
export type None = {
_tag: "None";
};
export type Option<A> = Some<A> | None;
const n1: Option<number> = { _tag: "Some", value: 1 };
export const some = <A>(value: A): Option<A> => ({ _tag: "Some", value });
export const none = (): None => ({ _tag: "None" });
export const isSome = <A>(oa: Option<A>): oa is Some<A> => oa._tag === "Some";
export const isNone = <A>(oa: Option<A>): oa is None => oa._tag === "None";
이렇게 타입을 정하는 이유는 값의 부재를 선택적인 속성을 처리하고
값의 부재를 명시적으로 다루기 위함입니다. 해당코드는 아래코드에서 사용이 될텐데요,
export const fromUndefined = <A>(a: A | undefined): Option<A> => {
if (a === undefined) return none();
return some(a);
};
export const getOrElse = <A>(oa: Option<A>, defaultValue: A): A => {
if (isNone(oa)) return defaultValue;
return oa.value;
};
export const map = <A, B>(oa: Option<A>, f: (a: A) => B): Option<B> => {
if (isNone(oa)) return oa;
return some(f(oa.value));
};
값이 존재하면 Some으로 감싸고 부재하면 None을 반환하거나,
예상치 못한 undefined | null로 인한 오류를 방지하고 default값을 반환하여 안전하게 접근합니다.
ex) getOrElse(optionDiscountPrice, 0)
해당 코드들의 활용은 다음과 같습니다.
const stockItem = (item: Item): string => {
const optionDiscountPrice = O.fromUndefined(item.discountPrice); //값의부재를파악 some(a) | none을 반환
const discountPrice = O.getOrElse(optionDiscountPrice, 0); //값이없다면 default값
let saleText = "";
// let discountPrice = 0;
if (O.isSome(optionDiscountPrice)) {
//응용해서 다른값을 만들기 때문에 getOrElse로 구현 할수없다.
saleText = `${optionDiscountPrice}원 할인`;
}
return `
<li>
<h2>${item.name}</h2>
<div>가격: ${item.price - discountPrice}원 ${saleText}</div>
<div>수량: ${item.quantity}</div>
</li>
`;
};
const outOfStockItem = (item: Item): string => `
<li class="gray">
<h2>${item.name} (품절)</h2>
<div class="strike">가격: ${item.price}원</div>
<div class="strike">수량 : ${item.quantity}상자</div>
</li>
`;
이런식으로,
let saleText = "";
let discountPrice = 0;
if (item.discountPrice !== undefined) {
saleText = `${item.discountPrice}원 할인`;
discountPrice = item.discountPrice;
}
바로 위에 코드를 사용하는 대신 값이 undfined일경우 값의 부재를 명시적으로 다루고,
보다 안전하게 접근할수 있도록 할수 있습니다.
(참고)
*정적 타입 언어(Static Typing Language)
정적 타입 언어는 변수의 데이터 타입을 컴파일 시간에 결정하며, 코드 작성 시에 변수의 타입을 명시적으로 선언해야 합니다.
특징:
변수의 타입은 명시적으로 선언되므로 코드의 안정성과 가독성이 높아집니다.
컴파일러는 타입 불일치 에러를 미리 감지할 수 있으므로 런타임 오류를 방지합니다.
코드의 예측 가능성이 높아지며, 코드 자동 완성, 리팩토링 도구 등이 타입 정보를 활용하여 도움을 줄 수 있습니다.
예시 언어: TypeScript, Java, C++, C#, Kotlin 등이 정적 타입 언어에 속합니다.
vs 동적타입언어(Dynamic Typing Language)
동적 타입 언어는 변수의 데이터 타입을 런타임 시에 결정하며, 코드 작성 시에 변수의 타입을 명시적으로 선언할 필요가 없습니다.
예시 언어: JavaScript, Python, Ruby, PHP 등이 동적 타입 언어에 속합니다.
특징:
변수의 타입은 실행 시간에 결정되므로 코드 작성이 유연합니다.
런타임 시 타입 불일치 에러가 발생할 수 있으며, 이를 방지하기 위해 명시적인 타입 검사를 추가로 수행해야 할 수 있습니다. 코드가 짧고 간결할 수 있으며, 빠른 개발 및 프로토타이핑에 적합합니다.
읽어주셔서 감사합니다 :)