본문 바로가기
Develog/Front

[리팩터링]Object.keys() 타입 지정해서 사용하기

by 예 강 2023. 7. 23.
type CoffeePrice = {
  [K in CoffeeName]: number;
};

type CoffeeName = "americano" | "latte" | "ade";

const obj: CoffeePrice = {
//    ~~~ error Property 'ade' is missing in type '{ americano: number; latte: number; }' but required in type 'CoffeePrice'.ts(2741
  americano: 10,
  latte: 10,
};
  • ade 가 없어서 완전히 일치하지 않기 때문에 오류가 나온다.

해결법

? 연산자를 넣어주거나

 

부분만 포함하겠다는 partial 키워드를 넣어주면 된다.

 

위의 기초 연습을 토대로 내 코드를 리팩터링 하기로 했다.

 

 


 

문제의 코드,tf를 이용해 type 가드를 해줬음에도 오류가 난다.

 

type은 잘 추론하고 있다

Partial키워드의 타입은 이렇다.

Partial 키워드를 사용하면 undefined도 올 수 있다.

하지만 위의 코드에서 나는 tf = type&&propertyValues 를 이용해 타입가드를 했는데도 undefined로 추론하고 있는데 왜 오류가 나는걸까 ?

 

 

심지어 테스트 코드로 테스트해보시 Partial 키워드를 사용하는 d 에 값을 할당하는건 문제가 없었다.

그럼 대체뭐지?

type의 타입인 HousePriceObjectType을 살펴보자

 

나는 여기서 문제를 생각했다 …

나는 houseType을 통해 나온 값인 propertyValues 와 type 객체가

같은 key값을 가진다는걸 알고있다.

 

하지만 ts는 서로 다른 함수에서 태어난 두 값을 연관시켜서 추론하지 못하는거다

 

같은 HousePriceType을 사용한다고 해도

type의 키값엔 kbPrice가 있어도

 

PropertyValues엔 kbPrice가 없을 수도 있으니까!

계속 Undefined가 떳던 것이다.

 

그림으로 설명해보자면 

 

 

그렇다면 해결방법은 ?

이런식으로 type.buildingPrice처럼 타입가드를 하나하나 걸어주면 해결된다.

이런방식으로 하나하나 타입가드를 거는건 된다. 다만 type[type] 지정은 되지않는다.

 

로직을 단순하게 보기위해 비슷한 환경을 구성했다.

 

type CoffeePrice = {
  [K in CoffeeName]: number;
};

type CoffeeName = "americano" | "latte" | "ade" | "blackcoffee";

type PriorityType = {
  table1: Partial<CoffeePrice>;
  table2: Partial<CoffeePrice>;
};
const PRIORITY: PriorityType = {
  table1: {
    americano: 1,
    latte: 1,
  },
  table2: {
    americano: 1,
    latte: 2,
  },
};
const returnFunction = (
  c: "table1" | "table2"
): PriorityType[keyof PriorityType] => {
  return PRIORITY[c];
};

const cafe = (d: Partial<CoffeePrice>) => {
  const c = "table1";
  const a = returnFunction(c);
  let priority: number = 1000;
  for (const key of Object.keys(d) as Array<CoffeeName>) {
    if (a[key]) {
      priority = a[key]; 
      ~~~~~~~~~~ error
      console.log(key);
    }
    console.log(key);
    d[key] = 10;
  }
};

 

비슷한 로직으로 만든 다른환경 역시나 에러가 난다.

 

 

이렇게 세조각으로 나누고 type을 분명하게 해줬다.

 

그리고 스택오버플로우에 Object.keys()의 타입을 구하는법을 검색해봤는데 as Array<keyof typeof type> 을 쓰면된다고한다.

 

예를들어 MultiApartOfficeElderHousePriorityType 타입이라면

즉 type의 typeof 인 MultiApartOfficeElderHousePriorityType 의 key 값인

 

const calculateHousePriceByPriority = (
  houseType: HouseType,
  propertyValues: Partial<HousePricesType>,
  housePrices: HousePricesType
) => {
  let priority: number | undefined = 1000;
  let housePrice = 0;

  let type = findPriorityType(houseType);
  for (const key of Object.keys(type) as Array<keyof typeof type>) {
    if (type[key] < priority) {
      priority = type[key];
      housePrice = calculateHousePrice(
        key,
        propertyValues[key]!.value,
        housePrices
      );
      housePrice *= LOAN_LATIO;
    }
  }

  return housePrice;
};

 

 

 as Array<keyof typeof type> 는

예를들어 MultiApartOfficeElderHousePriorityType 타입이라면

즉 type의 typeof 인 MultiApartOfficeElderHousePriorityType 의 key 값인

kbPrice … 을 가져오는거다.

그리고 그걸 배열로 만들어 Object.keys의 타입으로 선언해준다.

 

매번 저 긴코드를 치기도 귀찮고 보기도 좋지 않아서 

 

이런식으로 util 함수로 만들었다.

 

 

그리고 위처럼 리팩터링했다! 끝!