문제 상황


아래와 같은 타입이 있다고 가정

export type OrderStatus = 'pending' | 'new' | '...생략'
export type Client = { user_id: number; company_name: string; };

export type OrderFilterParams = {
  status: Array<OrderStatus>;
  client: Array<Client>;
	// ...생략
};

ClientAndOrderFilter 컴포넌트에선 "status" | "client" 두 종류의 타입을 받아 params[type] 형태로 OrderFilterParams 객체에 접근해서 값을 변경해야 하는 상황

interface ClientAndOrderFilterProps {
	setParams: Dispatch<SetStateAction<OrderFilterParams>>;
  params: OrderFilterParams;
  type: "status" | "client"
	// ...
}

하지만 ClientAndOrderFilter 컴포넌트에서 어떤 종류의 type("status" | "client")을 받을지 타입스크립트는 알 수 없기 때문에 params[type] 형태로 접근하면 타입 추론이 이뤄지지 않아 에러 발생

해결 방안


아래처럼 식별자 영역에선 type("status" | "client") Prop 타입으로 T제약 조건을 지정하고, 구현부에선 T 타입에 따라 다른 값을 반환하는 조건부 타입(OrderStatus[] | Client[])을 사용하면 문제를 해결할 수 있음

// 변경 전 (각 key에 할당될 값을 고정하지 않았으므로 수정 필요)
export type OrderFilterParams = { [key in OrderFilterType]?: Array<OrderStatus | ISODateString | ClinicLabType> };

// 변경 후
export type OrderFilterParams = {
  status: Array<OrderStatus>;
  client: Array<Client>;
  startdate: Array<ISODateString>;
  enddate: Array<ISODateString>;
};
export type ListType = "status" | "client";

// OrderStatus[] / Client[] 2가지 종류의 배열을 받으므로 제네릭 사용해서 타입 가드
// <T = ListType> 부분은 타입 식별자. "status" | "client"를 T의 기본값으로 지정
// Array<T extends ...> 부분은 타입 구현부. T를 "status"로 받으면 OrderStatus[] 타입을 리턴하고 그 외엔 Client[] 타입 리턴
export type ListFilter<T = ListType> = Array<T extends "status" ? OrderStatus : Client>;

이제 params[type]의 타입을 ListFilter<typeof type>으로 지정하면 타입 에러 해결됨 ✨

	const clickHandler = (status: ListFilterStatus) => {

	setParams((prevParams) => {
	  const params: ListFilter<typeof type> = prevParams[type];
		// ...
	  return {
	    ...prevParams,
	    [type]: params.filter(param => /* ... */)
	  };
	});
};