프로젝트 진행하면 상숫값 관리할 때 객체를 사용
컴포넌트나 함수에서 이런 객체를 사용할 때 열린 타입으로 설정 가능
열린 타입
: 추가적인 속성이나 값이 포함될 수 있는 타입을 의미해. 즉, 정의된 속성 외에 다른 속성도 허용되는 타입
함수 인자로 키를 받아서 value를 반환하는 함수를 보면...
: 키 타입을 해당 객체에 존재하는 키값으로 설정하는 것이 아니라
string으로 설정 -> getColorHex 함수의 반환 값 = any
이유) colors에 어떤 값이 추가될지 모르기 때문...
const colors {
red : "#F45452",
green : "#0C952A",
};
const getColorHex = (key : string) => colors[key];
여기서 as const로 객체를 불변 객체로 선언하고, keyof 연산자를 사용하여 getColorHex 함수 인자로 실제 colors객체에 존재하는 키값만 받도록 설정가능.
.
.
.
Atom 단위의 작은 컴포넌트( Button, Header, Input 등 )는 폰트 크기, 폰트 색상, 배경 색상 등 다양한 환경에서 우연하게 사용될 수 있도록 구현 -> props로 넘겨주도록 설정.
: 그러면 사용자가 모든 값을 인지해야 함 & 변경사항 직접 찾아서 직접 수정
-> 번거로움 , 변경에 취약한 상태
해결 : 해당 프로젝트의 스타일 값을 관리해주는 theme 객체를 두고 관리함.
theme 객체로 타입을 구체화하려면 keyof, typeof 연산자가 타입스크립트에서 어떻게 사용되는 지 알아야 함.
.
.
.
타입스크립트에서 keyof 연산자는 객체 타입을 받아 해당 객체의 키값을 string 또는 number의 리터럴 유니온 타입을 반환.
keyof 연산자는 객체 타입을 받음.
-> 객체의 키값을 타입으로 다루려면 값 객체를 타입으로 변환해야 함 : typeof 연산자 활용
타입스크립트 typeof 연산자는 단독 사용 보다는 주로 ReturnType같이 유틸리티 타입이나 keyof 연산자같이 타입을 받는 연산자와 함께 쓰임.
theme뿐만 아니라 여러 상숫값을 props 로 받은 다음에 객체의 키값을 추출한 타입을 활용하면 객체에 접근할 때 타입스크립트의 도움을 받아 실수 방지 가능.
객체 선언 시 키가 어떤 값인지 명확하지 않다면 Record의 키를 string이나 number 같은 원시 타입으로 명시
타입스크립트는 키가 유효 x 라도 타입상으로는 문제 x -> 오류 x
--> 이러면 런타임에 예상치 못한 에러 발생 가능
.
.
.
Category 타입 : string
Category를 Record의 키로 사용하는 foodByCategory 객체는 무한한 키 집합을 가지게 됨.
이때 foodByCategory 객체에 없는 키값을 사용하더라도 타입스크립트는 오류 표시 x
foodByCategory["양식"]; // FoodD로 추론
foodByCategory["양식].map(food) => console.log(food.name)); // 오류가 발생하지 않는다
그러나 foodByCategory["양식"] : 런타임에서 undefined -> 오류 반환.
foodByCategory["양식"].map((food) => console.log(food.name)); // Uncaught Typearror:Cannot read properties of undefined (reading 'map')
이때 자바스크립트의 옵셔널 체이닝 등을 사용 -> 런타임 에러 방지 가능
옵셔널 체이닝 optional chaining
: 객체의 속성을 찾을 때 null 또는 undefined가 있어도 오류 없이 안전하게 접근하는 방법.
?. 문법으로 표현, 옵셔널 체이닝을 사용할 대 중간에 null 또는 undefined인 속성이 있는지 검사함.
속성 존재 -> 반환 / 속성 존재 x -> undefined 반환
foodByCategory ["양식"]?.map((food) => console.log(food.name));
그러나 어떤 값인지 undefined인지 매번 판단해야 하는 번거로움 발생
하지만 타입스크립트의 기능을 활용 -> 개발 중에 유효하지 않은 키가 사용되었는지 또는 undefined일 수 있는 값이 있는지 등을 사전 파악 가능
키가 유한한 집합 -> 유닛 타입 ( 다른 타입으로 쪼개지지 않고 오직 하나의 정확환 값의 타입 ) 사용 가능
type Category = 한식"| "일식";
interface Food {
name: string;
//...
}
const foodByCategory: Record‹Category, Food[]> = {
한식: [{ name: "제육덮밥" }, { name: "뚝배기 불고기" }],
일식: [{ name: "초밥" }, { name: "텐동" H1, }];// Property 'gAl' does not exist on type 'Record‹Category, Food[]>foodByCategory["양식"];
이제 Category로 -> 한식 또는 일식만 올 수 있음. -> 양식을 키로 사용하면 에러 발생
: 유닛 타입 화용 -> 개발 중에 유효하지 않은 키가 사용되었는지 확인 가능.
그러나 키가 무한해야 하는 상황에는 적합x
type PartialRecord < K extends string, T> = Partial <Record, T>>;
type Category = string;
interface Food {
name: string;
//...
}
const foodByCategory: PartialRecord <Category, Food[]> = {
한식: [{ name: "제육덮밥" }, { name: "뚝배기 불고기" }],
일식: [{ name: "초밥" }, { name: "텐동" }],
};
foodByCategory["양식"]; // FoodD 또는 undefined 타입으로 추론
foodByCategory ["©EA|"].map (food) => console.log(food.name)); // Object is possibly'undefined'
foodByCategory["양식"]?.map((food) => console.Log(food.name)); // OK
타입스크립트 foodCategory[key]를 Food[] 또는 undefined로 추론
...이 값은 개발자에게 이 값은 undefined일 수 있으나 처리가 필요하다고 표시
-> 사전에 조치할 수 있게 되어 런타임 오류 줄일 수 있음.
도서참조 : 우아한 타입스크립트 with 리액트