하위 태스크 1
기본 타입 호환성
리터럴 타입과 기본 타입 간 업캐스팅/다운캐스팅 테스트
리터럴 타입의 값을 기본 타입의 변수에 할당하는 업 캐스팅은 가능하지만. 기본 타입의 값을 리터럴 타입의 변수에 할당하는 다운 캐스팅은 불가능하다.
src/compatibility.ts:
const numberTen: number = 10;
const literalTen: 10 = 10;
let number: number = literalTen;
let literal: 10 = numberTen; // Type 'number' is not assignable to type '10'.하위 태스크 2
객체 타입 호환성
Animal/Dog 타입으로 슈퍼타입-서브타입 관계 확인
Dog 타입은 Animal 타입에 hungry 속성이 더해진 타입이다. 구조적인 관점에서 Dog 타입은 Animal 타입의 서브 타입이다. Dog 타입의 값은 Animal 타입의 변수에 할당할 수 있다. 그러나 반대는 불가능하다.
src/compatibility.ts:
// ...
type Animal = {
name: string,
age: number,
};
type Dog = {
name: string,
age: number,
hungry: boolean,
};
const kong: Animal = {
name: "콩",
age: 4,
};
const nuri: Dog = {
name: "누리",
age: 3,
hungry: true
};
let animal: Animal;
animal = kong;
animal = nuri;
let dog: Dog;
dog = kong; // Property 'hungry' is missing in type 'Animal' but required in type 'Dog'.
dog = nuri;하위 태스크 3
초과 프로퍼티 검사
직접 할당 vs 변수 할당 시 검사 차이 확인
변수 선언 후 별도의 문장에서 할당할 때는 초과 속성 검사를 하지 않지만, 변수 선언과 함께 객체 리터럴로 초기화할 때는 초과 속성에 대한 엄격한 타입 검사가 이루어진다.
src/compatibility.ts:
// ...
const kong: Animal = {
name: "콩",
age: 4,
bark: "bowwow!", // Object literal may only specify known properties, and 'bark' does not exist in type 'Animal'.
};하위 태스크 4
타입 추론 확인
타입 주석 없이 변수 선언 후 추론된 타입 확인
const 키워드로 선언된 변수는 타입 유추가 구체적으로 이루어진다. 리터럴로 변수 초기화가 이루어지면 해당 리터럴 타입으로 유추된다.
let 키워드로 선언된 변수는 타입 유추가 추상적으로 이루어진다. 리터럴로 변수 초기화가 이루어지면 해당 리터럴 타입의 기본 타입으로 유추된다.
src/type-narrowing.ts:
const cString = "Hello"; // "Hello"
const cNumber = 10; // 10
const cBoolean = true; // true;
let lString = "Hello"; // string
let lNumber = 10; // number
let lBoolean = true; // boolean하위 태스크 5
typeof 타입 가드
typeof로 원시 타입 구분 및 타입 좁히기
src/type-narrowing.ts:
// ...
const people = [
{
id: 1,
name: "홍길동",
},
{
id: 2,
name: "지유정",
},
];
function getPerson(idOrName: number | string) {
if (typeof idOrName === "number") {
return people.find((p) => p.id === idOrName);
}
if (typeof idOrName === "string") {
return people.find((p) => p.name === idOrName);
}
}
console.log(getPerson(1)); // { id: 1, name: '홍길동' }
console.log(getPerson("지유정")); // { id: 2, name: '지유정' }하위 태스크 6
instanceof 타입 가드
instanceof로 클래스 타입 확인
src/type-narrowing.ts:
function printDate(date: unknown) {
if (!(date instanceof Date)) {
console.error("Date 자료형이 아닙니다.");
return;
}
console.log(String(date));
}
printDate("2026-03-06"); // Date 자료형이 아닙니다.
printDate(new Date("2026-03-06")); // Fri Mar 06 2026 09:00:00 GMT+0900 (Korean Standard Time)하위 태스크 7
in 연산자 타입 가드
in으로 객체 프로퍼티 존재 확인
src/type-narrowing.ts:
function validateProperties(value: unknown) {
if (!(typeof value === "object" && value !== null)) {
console.error("전달된 인수는 object 자료형이 아닙니다.");
return;
}
if (!("name" in value)) {
console.error("name 속성이 존재하지 않습니다.");
return;
}
if (!("age" in value)) {
console.error("age 속성이 존재하지 않습니다.");
return;
}
}
validateProperties(null); // 전달된 인수는 object 자료형이 아닙니다.
validateProperties({ age: 10 }); // name 속성이 존재하지 않습니다.
validateProperties({ name: "홍길동" }); // age 속성이 존재하지 않습니다.하위 태스크 8
유니온 타입 실습
여러 타입 중 하나를 허용하는 유니온 타입 사용
src/algebraic-types.ts:
type IdOrName = string | number;
const userId: IdOrName = 1;
const userName: IdOrName = "홍길동";
function echo(value: IdOrName) {
console.log(value);
}
echo(userId); // 1
echo(userName); // 홍길동
echo({}); // Argument of type '{}' is not assignable to parameter of type 'IdOrName'.하위 태스크 9
인터섹션 타입 실습
모든 프로퍼티를 포함하는 인터섹션 타입 사용
src/algebraic-types.ts:
// ...
type Person = {
name: string,
sleep: boolean,
};
type Mammal = Dog & Person;
const mammal: Mammal = {
name: "Dee",
hungry: true,
sleep: false,
};하위 태스크 10
서로소 유니온 타입
태그 프로퍼티로 타입 구분, switch문 활용
src/algebraic-types.ts:
// ...
type Admin = {
tag: "ADMIN",
name: string,
};
type Member = {
tag: "MEMBER",
organization: string,
};
type Guest = {
tag: "GUEST",
count: number,
};
function who(anonymous: Admin | Member | Guest) {
switch (anonymous.tag) {
case "ADMIN": {
console.log("안녕하세요, 관리자님.");
return;
}
case "MEMBER": {
console.log("안녕하세요, 회원님.");
return;
}
case "GUEST": {
console.log("안녕하세요, 방문자님.");
return;
}
default: {
console.error("당신은 누군가요?");
}
}
}
who({ tag: "ADMIN", name: "최서유" }); // 안녕하세요, 관리자님.
who({ tag: "MEMBER", organization: "E마켓" }); // 안녕하세요, 회원님.
who({ tag: "GUEST", count: 2 }); // 안녕하세요, 방문자님.하위 태스크 11
타입 단언 규칙
타입 단언의 호환성 규칙 확인
빈 객체는 Person과 구조적 기원이 같으므로 as 키워드로 타입 단언할 수 있다.
src/type-assertion.ts:
type Person = {
name: string,
age: number,
};
const person: Person = {} as Person;변수 선언과 동시에 초기화할 경우, 초과 속성이 있으면 오류가 발생한다. as 타입 단언을 통해 오류를 우회할 수 있다.
// ...
const otherPerson: Person = {
name: "진형석",
age: 25,
hungry: true
} as Person;TypeScript의 unknown은 모든 타입의 조상인 Top 타입이고, never는 모든 타입의 후손인 Bottom 타입이다. as 타입 단언은 두 타입이 계층 구조상 연결되어 있으면 단언을 허용한다. 따라서 숫자 타입의 값은 unknown 또는 never로 타입 단언할 수 있다.
src/type-assertion.ts:
const numOne = 100 as never;
const numTwo = 100 as unknown;하위 태스크 12
const/Non Null 단언
const 단언과 ! 연산자 사용
as const 타입 단언은 매우 구체적인 타입 유추를 수행한다. 원시형 값은 리터럴로 타입이 유추되고, 참조형 값은 각 속성이 readonly이고 속성 값이 리터럴로 타입이 유추된다.
src/type-assertion.ts:
let counter = 10 as const;
// let counter: 10
type Dog = {
name: string,
age: number,
hungry?: boolean,
};
const dogOne = {
name: "Soo",
age: 3,
} as const;
// const dogOne: {
// readonly name: "Soo";
// readonly age: 3;
// }
const dogTwo: Dog = {
name: "Doe",
age: 14,
};
const hungry: boolean = dogTwo.hungry!;