최근에 진행 중인 Effitizer 프로젝트에서 기존에 작성된 코드를 분석하던 중에 as keyof typeof
라는 표현을 발견했다. 작성하신 개발자 분에게 직접 여쭤보고 다음과 같은 내용을 알게 되었다.
기존 코드는 다음과 같은 형태였다.
소셜 로그인을 하기 위한 버튼을 렌더링하는 로그인 페이지 컴포넌트이다.
const providerInfo = {
google: { name: 'Google', Icon: GoogleIcon },
kakao: { name: '카카오', Icon: KakaoIcon },
naver: { name: '네이버', Icon: NaverIcon },
};
...
const { name, Icon } = providerInfo[provider.id as keyof typeof providerInfo];
여기서 as keyof typeof
부분이 궁금했다.
우선 as keyof typeof providerInfo
부분을 지우면 providerInfo[provider.id]
에 다음과 같은 에러가 발생한다.
Element implicitly has an 'any' type because expression of type 'LiteralUnion<BuiltInProviderType, string>' can't be used to index type '{ google: { name: string; Icon: (props: SVGProps) => Element; }; kakao: { name: string; Icon: (props: SVGProps) => Element; }; naver: { ...; }; }'.
이 문제를 해결하려면 providerInfo
객체의 '키'인 provider.id
의 타입을 지정해주어야 했다.
as
는 타입 단언에 쓰이는 키워드이다.
keyof
는 '(객체의) 키의 타입을 정한다'는 뜻이다.
typeof
는 자바스크립트에서도 사용하는 '~의 타입'을 알려주는 키워드이다.
즉, as keyof typeof providerInfo
부분을 한 단어씩 해석하면
providerInfo
객체의 타입은typeof providerInfo
로 알아내고, 앞에 keyof를 붙이면providerInfo
객체의 '키'의 타입으로provider.id
의 타입을 '단언'해줘('as')
라는 뜻이 된다.
이렇게 하면 컴포넌트 상단에 'type ProviderInfo ~' 또는 'interface ProviderInfo ~' 하는 식으로 명시적으로 지정하지 않고도 키워드를 통해 타입을 '서술적으로' 지정할 수 있게 된다.
as keyof typeof
가 가독성이 좋지 않을 것 같으면 다음과 같이 리팩토링이 가능하다.
const providerInfo = {
google: { name: 'Google', Icon: GoogleIcon },
kakao: { name: '카카오', Icon: KakaoIcon },
naver: { name: '네이버', Icon: NaverIcon },
};
type ProviderInfoKey = keyof typeof providerInfo;
...
const { name, Icon } = providerInfo[provider.id as ProviderInfoKey];