Quiz 1.
타입 단언을 이용해 person 변수에 빈 객체를 할당하세요
(힌트. 초과 프로퍼티 검사 방지를 위한 타입 단언)
type Person = {
name: string;
age: number;
};
let person: Person = {};
Answer
let person = {} as Person;
person.name = "치현";
person.age = 29;
Quiz 2.
타입 단언을 이용해 함수 호출에서의 오류를 해결하세요
(힌트. const 단언)
let value = 10;
giveMe10(value); // error: 'number' 타입의 인수는 '10' 타입의 매개변수에 할당할 수 없다.
function giveMe10(value: 10) {
return value;
}
Answer
let value1 = 10 as const;
Quiz 3.
다음 요구사항을 만족하는 코드를 작성하세요
- CompanyMember 타입을 Boss와 Employee의 서로소 유니온 타입으로 정의하세요
type Boss = {
car: string;
};
type Employee = {
salary: number;
};
type CompanyMember = Employee | Boss;
Answer
type Boss = {
type: "BOSS";
car: "string";
};
type Employee = {
type: "EMPLOYEE";
salary: number;
};
type CompanyMember = Employee | Boss;
배운 개념 정리
타입 단언
정의
타입 단언(Type Assertion)은 프로그래머가 TypeScript 컴파일러에게 특정 변수가 특정 타입임을 명시적으로 알려주는 방법이다.
(타입 단언은 타입스크립트 컴파일러의 눈을 잠시 가리는 것이기에, 타입 단언을 남발하면 타입스크립트의 장점을 잃어버릴 수 있다.)
규칙
- 값 as 단언 <- 단언식 / A as B
- A가 B의 슈퍼타입이거나, 서브타입이어야 한다.
필요성
타입 단언은 프로그래머가 컴파일러보다 더 정확한 타입 정보를 알고 있을 때 필요하다. 예를 들어, any 또는 unknown 타입의 변수에 대해 프로그래머가 더 구체적인 타입 정보를 알고 있을 때, 이 정보를 컴파일러에게 알려주기 위해 타입 단언을 사용한다.
사용법
- as 키워드 사용
Ex1 type Person1 = { name: string; age: number; }; let person1 = {} as Person1; person1.name = "치현"; person1.age = 29;
// Ex2 type Dog = { name: string; color: string; };
let dog = { name: "멍멍이", color: "검정색", breed: "진도", } as Dog;
- const 단언
```ts
let num5 = 10 as const;
let cat = {
name: "냥냥이",
color: " yellow",
} as const;
// readOnly이므로 변경 불가능
// cat.name = ""
타입 좁히기
let post: Post = { title: "게시글1", author: "치현", }; // author가 undefined일 수 있으므로, 옵셔널 체이닝을 사용하여 undefined일 경우 undefined를 반환하도록 한다.
// const len: number = post.author?.length; // Non Null 단언을 사용하여, author가 undefined가 아님을 단언한다.
const len: number = post.author!.length;
const len1: number = (post.author as string).length;
type Post = { title: string; author?: string; };
정의
타입 좁히기(Type Narrowing)는 더 넓은 범위의 타입에서 더 좁은 범위의 타입으로 변경한다. TypeScript 컴파일러는 조건문, 타입 가드 등을 통해 변수의 타입 범위를 좁힐 수 있다.
필요성
타입 좁히기는 여러 타입 중 한 가지 타입에 대해 작업을 수행하려 할 때 필요하다. 예를 들어, 유니온 타입의 변수에 대해 특정 타입의 메서드를 호출하려면, 먼저 해당 변수의 타입이 해당 메서드를 가진 타입인지 확인해야 한다. 이런 경우에 타입 좁히기를 사용하여 안전하게 메서드를 호출할 수 있다.
사용법
type Person = {
name: string;
age: number;
};
// value => number: toFixed
// value => string: trim, toUpperCase, toLowerCase
// value => Date: getTime, toDateString, toTimeString
// value => Person: name은 age살 입니다.
function func(value: number | string | Date | null | Person) {
value;
value.toUpperCase(); // 에러: string|number 형식에 'toUpperCase' 속성이 없습니다.
value.trim(); // 에러: string|number 형식에 'trim' 속성이 없습니다.
// 타입 가드
// 타입스크립트가 타입을 좁혀나가는 과정
if (typeof value === "number") {
value.toFixed(2);
} else if (typeof value === "string") {
value.trim();
} else if (value instanceof Date) {
// Date는 node에 저장되어있는 내장객체로, instanceof를 사용하여 타입을 좁힐 수 있다.
// typeof value === "object"
// value는 null일 수도 있다.
// value.getTime();
value.getTime();
} else if (value && "age" in value) {
// Person 타입은 사용자가 직접 만든 타입이므로, typeof나 instanceof를 사용할 수 없다.
// Person 타입은 name과 age를 가지고 있으므로, in 연산자를 사용하여 타입을 좁힐 수 있다.
// value가 null이 될 수도 있으므로, null 체크를 해줘야한다.
console.log(`${value.name}은 ${value.age}살 입니다.`);
}
}
서로소 유니온 타입
정의
서로소 유니온 타입(Disjoint Union Type = Tagged Union Type)은 각각의 유니온 멤버가 고유한 태그 또는 리터럴 타입의 프로퍼티를 가지고 있는 유니온 타입.
교집합이 없는 타입들로만 구성된 유니온 타입.
필요성
서로소 유니온 타입은 여러 다른 타입을 유연하게 처리할 수 있게 해준다. 각 타입이 고유한 태그를 가지고 있기 때문에, 타입 가드와 같은 방법으로 어떤 타입인지를 확인하고 해당 타입에 맞는 로직을 수행할 수 있다. 이는 코드의 안정성을 높이고, 런타임 에러를 방지하는 데 도움이 된다.
사용법
// Ex1
// tag가 Admin이면서 Member일 수 없기에, 서로소 유니온 타입이다.
type Admin = {
tag: "ADMIN";
name: string;
kickCount: number;
};
type Member = {
tag: "MEMBER";
name: string;
point: number;
};
type Guest = {
tag: "GUEST";
name: string;
visitCount: number;
};
type User = Admin | Member | Guest;
// 형식
// Admin -> {name}님 현재까지 {kickCount}번 강퇴했습니다.
// Member -> {name}님 현재까지 {point}를 모았습니다.
// Guest -> {name}님 현재까지 {kickCount}번 강퇴했습니다.
function login(user: User) {
switch (user.tag) {
case "ADMIN": {
console.log(`${user.name}님 현재까지 ${user.kickCount}번 강퇴했습니다.`);
break;
}
case "MEMBER": {
console.log(`${user.name}님 현재까지 ${user.point}를 모았습니다.`);
break;
}
case "GUEST": {
console.log(`${user.name}님 현재까지 ${user.visitCount}번 방문했습니다.`);
break;
}
}
// 아래와 같은 방식은 타입을 바로 알아볼 수 없기에 가독성이 떨어짐.
// if ("kickCount" in user) {
// console.log(`${user.name}님 현재까지 ${user.kickCount}번 강퇴했습니다.`);
// } else if ("point" in user) {
// console.log(`${user.name}님 현재까지 ${user.point}를 모았습니다.`);
// } else {
// console.log(`${user.name}님 현재까지 ${user.visitCount}번 방문했습니다.`);
// }
}
// Ex2: 비동기 작업 결과 처리 객체
type LoadingTask = {
state: "LOADING";
};
type FailedTask = {
state: "FAILED";
error: {
message: string;
};
};
type SuccessTask = {
state: "SUCCESS";
response: {
data: string;
};
};
type AsyncTask = LoadingTask | FailedTask | SuccessTask;
// 형식
// 로딩중 -> 콘솔에 로딩중 표시
// 실패 -> 실패: 에러메시지를 출력
// 성공 -> 성공: 데이터를 출력
function processResult(task: AsyncTask) {
switch (task.state) {
case "LOADING": {
console.log("로딩중");
break;
}
case "FAILED": {
console.log(`실패: ${task.error.message}`); // 선택적 프로퍼티 사용시 task.error가 undefined일 수 있으므로, task.error?.message로 작성해야한다.
break;
}
case "SUCCESS": {
console.log(`성공: ${task.response.data}`); // 선택적 프로퍼티 사용시 task.response가 undefined일 수 있으므로, task.response?.data로 작성해야한다.
break;
}
}
}
const loading: AsyncTask = {
state: "LOADING",
};
const failed: AsyncTask = {
state: "FAILED",
error: {
message: "오류 발생 원인은 !!",
},
};
const success: AsyncTask = {
state: "SUCCESS",
response: {
data: "데이터 ~~",
},
};
Quiz 1.
타입 단언을 이용해 person 변수에 빈 객체를 할당하세요
(힌트. 초과 프로퍼티 검사 방지를 위한 타입 단언)
type Person = {
name: string;
age: number;
};
let person: Person = {};
Answer
let person = {} as Person;
person.name = "치현";
person.age = 29;
Quiz 2.
타입 단언을 이용해 함수 호출에서의 오류를 해결하세요
(힌트. const 단언)
let value = 10;
giveMe10(value); // error: 'number' 타입의 인수는 '10' 타입의 매개변수에 할당할 수 없다.
function giveMe10(value: 10) {
return value;
}
Answer
let value1 = 10 as const;
Quiz 3.
다음 요구사항을 만족하는 코드를 작성하세요
- CompanyMember 타입을 Boss와 Employee의 서로소 유니온 타입으로 정의하세요
type Boss = {
car: string;
};
type Employee = {
salary: number;
};
type CompanyMember = Employee | Boss;
Answer
type Boss = {
type: "BOSS";
car: "string";
};
type Employee = {
type: "EMPLOYEE";
salary: number;
};
type CompanyMember = Employee | Boss;
배운 개념 정리
타입 단언
정의
타입 단언(Type Assertion)은 프로그래머가 TypeScript 컴파일러에게 특정 변수가 특정 타입임을 명시적으로 알려주는 방법이다.
(타입 단언은 타입스크립트 컴파일러의 눈을 잠시 가리는 것이기에, 타입 단언을 남발하면 타입스크립트의 장점을 잃어버릴 수 있다.)
규칙
- 값 as 단언 <- 단언식 / A as B
- A가 B의 슈퍼타입이거나, 서브타입이어야 한다.
필요성
타입 단언은 프로그래머가 컴파일러보다 더 정확한 타입 정보를 알고 있을 때 필요하다. 예를 들어, any 또는 unknown 타입의 변수에 대해 프로그래머가 더 구체적인 타입 정보를 알고 있을 때, 이 정보를 컴파일러에게 알려주기 위해 타입 단언을 사용한다.
사용법
- as 키워드 사용
Ex1 type Person1 = { name: string; age: number; }; let person1 = {} as Person1; person1.name = "치현"; person1.age = 29;
// Ex2 type Dog = { name: string; color: string; };
let dog = { name: "멍멍이", color: "검정색", breed: "진도", } as Dog;
- const 단언
```ts
let num5 = 10 as const;
let cat = {
name: "냥냥이",
color: " yellow",
} as const;
// readOnly이므로 변경 불가능
// cat.name = ""
타입 좁히기
let post: Post = { title: "게시글1", author: "치현", }; // author가 undefined일 수 있으므로, 옵셔널 체이닝을 사용하여 undefined일 경우 undefined를 반환하도록 한다.
// const len: number = post.author?.length; // Non Null 단언을 사용하여, author가 undefined가 아님을 단언한다.
const len: number = post.author!.length;
const len1: number = (post.author as string).length;
type Post = { title: string; author?: string; };
정의
타입 좁히기(Type Narrowing)는 더 넓은 범위의 타입에서 더 좁은 범위의 타입으로 변경한다. TypeScript 컴파일러는 조건문, 타입 가드 등을 통해 변수의 타입 범위를 좁힐 수 있다.
필요성
타입 좁히기는 여러 타입 중 한 가지 타입에 대해 작업을 수행하려 할 때 필요하다. 예를 들어, 유니온 타입의 변수에 대해 특정 타입의 메서드를 호출하려면, 먼저 해당 변수의 타입이 해당 메서드를 가진 타입인지 확인해야 한다. 이런 경우에 타입 좁히기를 사용하여 안전하게 메서드를 호출할 수 있다.
사용법
type Person = {
name: string;
age: number;
};
// value => number: toFixed
// value => string: trim, toUpperCase, toLowerCase
// value => Date: getTime, toDateString, toTimeString
// value => Person: name은 age살 입니다.
function func(value: number | string | Date | null | Person) {
value;
value.toUpperCase(); // 에러: string|number 형식에 'toUpperCase' 속성이 없습니다.
value.trim(); // 에러: string|number 형식에 'trim' 속성이 없습니다.
// 타입 가드
// 타입스크립트가 타입을 좁혀나가는 과정
if (typeof value === "number") {
value.toFixed(2);
} else if (typeof value === "string") {
value.trim();
} else if (value instanceof Date) {
// Date는 node에 저장되어있는 내장객체로, instanceof를 사용하여 타입을 좁힐 수 있다.
// typeof value === "object"
// value는 null일 수도 있다.
// value.getTime();
value.getTime();
} else if (value && "age" in value) {
// Person 타입은 사용자가 직접 만든 타입이므로, typeof나 instanceof를 사용할 수 없다.
// Person 타입은 name과 age를 가지고 있으므로, in 연산자를 사용하여 타입을 좁힐 수 있다.
// value가 null이 될 수도 있으므로, null 체크를 해줘야한다.
console.log(`${value.name}은 ${value.age}살 입니다.`);
}
}
서로소 유니온 타입
정의
서로소 유니온 타입(Disjoint Union Type = Tagged Union Type)은 각각의 유니온 멤버가 고유한 태그 또는 리터럴 타입의 프로퍼티를 가지고 있는 유니온 타입.
교집합이 없는 타입들로만 구성된 유니온 타입.
필요성
서로소 유니온 타입은 여러 다른 타입을 유연하게 처리할 수 있게 해준다. 각 타입이 고유한 태그를 가지고 있기 때문에, 타입 가드와 같은 방법으로 어떤 타입인지를 확인하고 해당 타입에 맞는 로직을 수행할 수 있다. 이는 코드의 안정성을 높이고, 런타임 에러를 방지하는 데 도움이 된다.
사용법
// Ex1
// tag가 Admin이면서 Member일 수 없기에, 서로소 유니온 타입이다.
type Admin = {
tag: "ADMIN";
name: string;
kickCount: number;
};
type Member = {
tag: "MEMBER";
name: string;
point: number;
};
type Guest = {
tag: "GUEST";
name: string;
visitCount: number;
};
type User = Admin | Member | Guest;
// 형식
// Admin -> {name}님 현재까지 {kickCount}번 강퇴했습니다.
// Member -> {name}님 현재까지 {point}를 모았습니다.
// Guest -> {name}님 현재까지 {kickCount}번 강퇴했습니다.
function login(user: User) {
switch (user.tag) {
case "ADMIN": {
console.log(`${user.name}님 현재까지 ${user.kickCount}번 강퇴했습니다.`);
break;
}
case "MEMBER": {
console.log(`${user.name}님 현재까지 ${user.point}를 모았습니다.`);
break;
}
case "GUEST": {
console.log(`${user.name}님 현재까지 ${user.visitCount}번 방문했습니다.`);
break;
}
}
// 아래와 같은 방식은 타입을 바로 알아볼 수 없기에 가독성이 떨어짐.
// if ("kickCount" in user) {
// console.log(`${user.name}님 현재까지 ${user.kickCount}번 강퇴했습니다.`);
// } else if ("point" in user) {
// console.log(`${user.name}님 현재까지 ${user.point}를 모았습니다.`);
// } else {
// console.log(`${user.name}님 현재까지 ${user.visitCount}번 방문했습니다.`);
// }
}
// Ex2: 비동기 작업 결과 처리 객체
type LoadingTask = {
state: "LOADING";
};
type FailedTask = {
state: "FAILED";
error: {
message: string;
};
};
type SuccessTask = {
state: "SUCCESS";
response: {
data: string;
};
};
type AsyncTask = LoadingTask | FailedTask | SuccessTask;
// 형식
// 로딩중 -> 콘솔에 로딩중 표시
// 실패 -> 실패: 에러메시지를 출력
// 성공 -> 성공: 데이터를 출력
function processResult(task: AsyncTask) {
switch (task.state) {
case "LOADING": {
console.log("로딩중");
break;
}
case "FAILED": {
console.log(`실패: ${task.error.message}`); // 선택적 프로퍼티 사용시 task.error가 undefined일 수 있으므로, task.error?.message로 작성해야한다.
break;
}
case "SUCCESS": {
console.log(`성공: ${task.response.data}`); // 선택적 프로퍼티 사용시 task.response가 undefined일 수 있으므로, task.response?.data로 작성해야한다.
break;
}
}
}
const loading: AsyncTask = {
state: "LOADING",
};
const failed: AsyncTask = {
state: "FAILED",
error: {
message: "오류 발생 원인은 !!",
},
};
const success: AsyncTask = {
state: "SUCCESS",
response: {
data: "데이터 ~~",
},
};