Jieunny의 블로그
Section 6. 고급 타입 본문
📣 강의 내용 정리
𝟭. 인터섹션 타입 (AND, OR이 아님!)
✔️ '&' : 두 가지 타입을 결합하는 방법(여러 개의 타입 정의를 하나로 합치기)
type Admin = {
name: string;
privileges: string[];
};
type Employee = {
name: string;
startDate: Date;
};
type ElevatedEmployee = Admin & Employee;
// 인터섹션 타입
const el: ElevatedEmployee = {
name: 'Max',
privileges: ['create-server'],
startDate: new Date()
}
➰ 인터페이스 상속과 관련이 있다.
➰ 위 코드에서 type을 interface로 바꾸고 ElevatedEmployee 가 위에 두 인터페이스를 extends 하게 해주면 같은 결과가 나온다.
➰ 기존 타입을 대체하지 않으면서 기존 타입에 새로운 필드를 추가하고 싶을 때
➰ Type A, Type B가 있을 때 A와 B를 인터섹션 하면 A타입이면서 B타입이라는 의미
✚ 유니언 타입
interface Person {
name: string;
age: number;
}
interface Developer {
name: string;
skill: string;
}
function introduce(someone: Person | Developer) {
someone.name; // O 정상 동작
someone.age; // X 타입 오류
someone.skill; // X 타입 오류
}
✚ 유니언 타입 + 인터섹션 타입
type Combinable = string | number;
type Numeric = number | boolean;
type Universal = Combinable & Numeric; // number
// number만 겹치기 때문이다.
✔️ Intersection → A & B : A타입이면서 B타입
✔️ Union → A | B : A타입, B 타입 둘 중 하나
𝟮. 타입가드에 대한 추가 정보
✔️ 타입가드 : 특정 속성이나 메소드를 사용하기 전에 그것이 존재하는지 확인하거나 타입을 사용하기 전에 이 타입으로 어떤 작업을 수행할 수 있는지를 확인하는 개념 또는 방식
✔️ 유니언 타입을 돕는다.
function add(a: Combinable, b: Combinable) {
if(typeof a === 'string' || typeof b === 'string') {
// 타입 가드 구문
return a.toString() + b.toString();
}
return a + b;
}
➰ 유니온 타입이 지닌 유연성을 활용할 수 있게 해주며 런타임 시 코드가 정확하게 작동하게 한다.
➰ 객체의 경우 instanceof 나 in / 다른 타입들은 typeof 를 사용할 수 있다.
𝟯. 구별된 유니언
✔️ 구별된 유니언 : 타입가드를 쉽게 구현할 수 있게 해주는 유니언 타입으로 작업을 수행할 때 사용할 수 있는 패턴
➰ 실제 존재하는 속성을 사용해서 어떤 유형의 객체와 작업하고 있는지 알 수 있다.
➰ 둘 다 kind 속성(구별 속성)을 가지고 있고, 이 속성에 대해 타입 가드 스타일의 검사(===, !==) 또는 switch를 사용하면 TS가 특정한 리터럴을 가진 객체를 대상으로 한다는 것을 알아차리고 타입 좁히기를 실행해준다
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Square | Rectangle;
function area(s: Shape) {
if (s.kind === "square") {
// 이것으로 TypeScript가 `s`가 `Square`임을 알게 됨 ;)
// 그러므로 `Square`의 멤버를 안전하게 사용할 수 있음 :)
return s.size * s.size;
}
else {
// `Square`가 아님? 그러면 TypeScript는
// 이것이 `Rectangle`일 수 밖에 없음을 알게 됨 ;)
// 그러므로 `Rectangle`의 멤버를 안전하게 사용할 수 있음 :)
return s.width * s.height;
}
}
📚 참고 :https://radlohead.gitbook.io/typescript-deep-dive/type-system/discriminated-unions
𝟰. 형 변환(Typecasting)
✔️ 형 변환 : 타입스크립트가 직접 감지하지 못하는 특정 타입의 값을 타입스크립트에 알려주는 역할
1️⃣ 변환하고자 하는 요소 앞이나 타입스크립트에 타입을 알려주고자 하는 위치 앞에 무언가를 추가하는 방법
const userInputElement = <HTMLInputElement>document.getElementById('user-input');
➰ <>다음에 오는 것이 무엇이든 타입스크립트는 HTMLInputElement라는 것을 알게 된다.
2️⃣ 형 변환하고자 하는 타입 다음에 무언가를 추가하는 방법
const userInputElement = document.getElementById('user-input')! as HTMLInputElement;
// 형 변환의 경우 null이 아님을 알려주는 !를 쓸 수 없다.
// !와 형 변환을 동시에 쓰게 되면 이것이 null이 되지 않는다는 걸 한 번 더 알려주게 되는 셈이다.
const userInputElement = document.getElementById('user-input') as HTMLInputElement;
if(userInputElement) {
(userInputElement as HTMLInputElement).value = 'Hi there!';
}
// 대신 이런식으로 쓸 수 있다.
𝟱. 인덱스 속성
✔️ 인덱스 타입 : 속성이 정해져 있지 않고 동적으로 처리해야 할 경우 사용할 수 있다.
interface Props {
[key: string]: string;
}
// 키를 문자열로 받고, 타입은 string으로 받겠다 라는 의미
➰ 대괄호로 시작해서 키를 정의할 수 있고, 키에 대응하는 타입을 정의할 수 있다.
const p: Props = {
a: "d",
b: "3"
};
p['a'] // 'd'
p[1] // 3
➰ value의 타입을 문자열로 정했기 때문에 숫자를 입력하면 에러가 난다.
📚 참고 : https://velog.io/@yhg0337/chap.8-%ED%83%80%EC%9E%85%EB%B3%84%EC%B9%AD-Index-Type
𝟲. 함수 오버로드
✔️ 함수 오버로드 : 동일한 함수에 대해 여러 함수 시그니처를 정의할 수 있는 기능
function add(a: number): number;
function add(a: number, b: number): number);
function add(a: Combinable, b: Combinable) {
...
}
➰ 타입스크립트가 자체적으로 반환 타입을 알 수 없는 경우에 유용하다.
➰ 함수가 지원할 수 있는 다양한 조합에 대해 어떤 것이 반환되는지 명확히 알 수 있다.
𝟳. 옵셔널 체이닝
✔️ 옵셔널 체이닝 : 프로퍼티 타입이 null 또는 undefined 인 경우 프로퍼티 명 뒤에 '?'를 추가한다.
interface ICompanyInfo {
name: string | null | undefined;
}
let obj: ICompanyInfo = {
name: null
};
console.log(`obj.name?.length : ${obj.name?.length}`);
➰ 이 경우 name의 값이 null이어도 에러가 나지않고 코드가 정상적으로 작동한다.
➰ 참조 값이 nullish(null과 undefined)하다면 에러가 아닌 undefined를 반환한다.
➕'?'를 사용하는 또 다른 경우
✔️ 선택적 프로퍼티
➰ 프로퍼티의 값이 필수가 아닌 경우 사용한다.
interface ICompanyInfo {
name: string;
chairman?: string;
}
let obj: ICompanyInfo = {
name: 'FaceBook'
};
➰ 이 경우, chairman 값을 생략해도 에러가 나지 않는다.
𝟴. Null 병합
✔️ '??' : null 병합 연산자
➰ null 이거나 undefined라면 폴백을 사용해야 한다는 의미
➰ null 이나 undefined를 매끄럽게 처리하는데 도움이 되는 기능
➰ 여러 피연산자 중 그 값이 '확정되어 있는' 변수를 찾을 수 있다.
➰ '??'는 우선순위가 낮으므로 사용할 때는 '()'를 함께 사용하는 게 좋다.
const userInput = undefined;
coonst storedData = userInput ?? 'DEFAULT';
console.log(storedData); // DEFAULT
a ?? b
// a가 null도 아니고 undefined도 아니면 a, 그 외의 경우는 b
✔️ '||'와 다른 점
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
➰ ??는 첫 번째 정의된(defined) 값을 반환한다.
💡 새로 알게 된 점
1. 타입가드, 선택적 체이닝, 널 병합에 대한 내용
'CodeStates > TS 스터디' 카테고리의 다른 글
Section8. 데코레이터 (0) | 2023.03.03 |
---|---|
Section 7. 제네릭 (0) | 2023.02.22 |
Section 5. 클래스 & 인터페이스 (0) | 2023.02.21 |
Section 4. 차세대 자바스크립트와 TypeScript (0) | 2023.02.17 |
Section 3. TypeScript 컴파일러(및 구성) (0) | 2023.02.15 |