4장 타입 확장하기 / 좁히기

4.1 타입 확장하기

4.1.1 타입 확장의 장점

/**
* 메뉴 요소 타입
* 메뉴 이룜, 이미지, 할인율, 재고 정보를 담고 있다
* */
interface BaseMenuItem {
    itemName: string | null;
    itemlmageUrl: string | null;
    itemDiscountAmount: number;
    stock number | null;
}
/**
* 장바구니 요소 타입
* 메뉴 타입에 수량 정보가 추가되었다
* */
interface BaseCartltem extends BaseMenuItem {
    quantity number
}
type BaseMenuItem = {
    itemName string | null;
    itemlmageUrl string | null;
    itemDiscountAmount: number;
    stock number | null;
}
type BaseCartltem = {
    quantity number
} & BaseMenuItem;
/**
* 수정할 수 있는 장바구니 요소 타입
* 품절 여부, 수정할 수 있는 옵션 배열 정보가 추가되었다
* */
interface EditableCartItem extends BaseCartltem {
    isSoldOut: boolean;
    optionGroups; SelectableOptionGroup[];
}

/**
* 이벤트 장바구니 요소 타입
* 주문 가능 여부에 대한 정보가 추가되었다
* */
interface EventCartltem extends BaseCartltem {
    orderable boolean;
}

4.1.2 유니온 타입

type MyUnion = A | B;
interface CookingStep {
    orderld: string;
    price number;
}
interface DeliveryStep {
    orderld: string;
    time: number;
    distance: string;
}
function getDeliveryDistance(step CookingStep | DeliveryStep) {
    return step.distance;
    // Property 'distance' does not exist on type 'CookingStep | DeliveryStep’
    // Property 'distance' does not exist on type 'CookingStep'
}

4.1.3 교차 타입

/* 배달 팁 */
interface DeliveryTip {
    tip string
}
/* 별점 */
interface StarRating {
    rate: number;
}
/* 주문 필터 */
type Filter = DeliveryTip & StarRating;

const filter Filter = {
    tip "1000원 이하",
    rate 4,
}
type IdType = string | number;
type Numeric = number | boolean;

type Universal = IdType & Numeric;

4.1.4 extends와 교차 타입

interface DeliveryTip {
    tip: number;
}
interface Filter extends DeliveryTip {
    tipstring;
    // Interface 'Filter' incorrectly extends interface 'DeliveryTip'
    // Types of property 'tip' are incompatible
    // Type 'string' is not assignable to type 'number'
}
type DeliveryTip = {
    tip: number;
}
type Filter = DeliveryTip & {
    tip string;
};

4.2 타입 좁히기 - 타입 가드

4.2.1 타입 가드에 따라 분기 처리하기

4.2.2 원시 타입을 추론할 때: typeof 연산자 활용하기

4.2.3 인스턴스화된 객체 타입을 판별할 때: instanceof 연산자 활용하기

interface Range {
start Date;
end Date;
}

interface DatePickerProps {
selectedDates?: Date | Range;
}
const DatePicker = ({ selectedDates } DatePickerProps) => {
    const [selected, setSelected] = useState(convertToRange(selectedDates));
    //...
}
export function convertToRange(selected? Date | Range) Range | undefined {
    return selected instanceof Date
    ? { start selected, end selected }
    : selected;
}

4.2.4 객체의 속성이 있는지 없는지에 따른 구분: in 연산자 활용하기

4.2.5 is 연산자로 사용자 정의 타입 가드 만들어 활용하기

const isDestinationCode = (x string) x is Destinationcode =>
    destinationCodeList.includes(x);

4.3 타입 좁히기 - 식별할 수 있는 유니온(Discriminated Unions)

4.3.1 에러 정의하기

type TextError = {
    errorCode string;
    errorMessage: string;
}
type ToastError = {
    errorCode: string;
    errorMessage string;
    toastShowDuration number; // 토스트를 띄워줄 시간
}
type AlertError = {
    errorCode; string;
    errorMessage string;
    onConfirm: () => void; // 얼럿 창의 확인 버튼을 누른 뒤 액션
};
type ErrorFeedbackType = TextError | ToastError | AlertError;
const errorArr ErrorFeedbackType[] = [
{ errorcode: "100", errorMessage "텍스트 에러"},
{ errorCode "200", errorMessage "토스트 에러", toastShowDuration 3000 },
{ errorcode "300", errorMessage "얼럿 에러", onConfirm () => {} },
]

const errorArr ErrorFeedbackType[] = [
    // ...
    {
    errorCode "999",
    errorMessage "잘못된 에러",
    toastShowDuration 3000,
    onConfirm () => {},
    }, // expected error
]

4.3.2 식별할 수 있는 유니온

type TextError = {
    errorType "TEXT";
    errorCode string;
    errorMessage string;
}
type ToastError = {
    errorType "TOAST";
    errorCode string;
    errorMessage: string;
    toastShowDuration: number;
}
type AlertError = {
    errorType "ALERT";
    errorCode string;
    errorMessage string;
    onConfirm () => void;
}

4.3.3 식별할 수 있는 유니온의 판별자 선정

4.4 Exhaustiveness Checking으로 점확한 타입 분기 유지하기

4.4.1 상품권

type Productprice = "10000" | "20000"
const getProductName = (productPrice ProductPrice) string => {
    if (productprice === "10000") return "배민상품권 1만 원";
    if (productPrice === "20000") return "배민상품권 2만 원";
    else {
        return "배민상품권";
    }
}
type Productprice = "10000" | "20000" | "5000";
const getProductName = (productPrice ProductPrice) string => {
    if (productprice === "10000") return "배민상품권 1만 원";
    if (productPrice === "20000") return "배민상품권 2만 원";
    if (productprice === "5000") return "배민상품권 5천 원"; // 조건 추가 필요
    else {
        return "배민상품권";
    }
}
type Productprice = "10000" | "20000" | "5000";
const getProductName = (productPrice ProductPrice) string => {
    if (productprice === "10000") return "배민상품권 1만 원";
    if (productPrice === "20000") return "배민상품권 2만 원";
    // if (productprice === "5000") return "배민상품권 5천 원"; // 조건 추가 필요
    else {
        exhaustiveCheck(productPrice); // Error: Argument of type 'string' is not assignable to parameter of type 'never'
        return "배민상품권";
    }
}

const exhaustiveCheck = (param never) => {
    throw new Error("type error!");
}

끝!