- 어떤 기준으로 타입을 정의하는지,
- 어떤 기준으로 타입간의 관계를 정의하는지,
- 어떤 기준으로 타입의 오류를 검사하는지
를 알고 작성하는 게 중요하다.
// unknown 타입 --> 전체 집합
function unknownExam(){
let a : unknown = 1;
let b : unknown = 'hello';
let c: unknown = true;
let d : unknown = null;
let e: unknown = undefined;
let unknownVar : unknown;
let num : number = unknownVar; // 오류
let str: string = unknownVar; // 오류
let bool : boolean = unknownVar; //오류
}
// never 타입 --> 모든 타입의 서브타입. 모든 타입의 부분집합 = 공집합
function neverExam() {
function neverFunc(): never {
while (true) {}
}
let num: number = neverFunc();
let str : string = neverFunc();
let bool : boolean = neverFunc();
let never1 : never = 10; //오류
let never2: never = 'string'; //오류
let never3: never = true; //오류
}
// any 타입
function anyExam(){
let unknownVar : unknown;
let anyVar : any;
let undefinedVar : undefined;
let neverVar : never
anyVar = unknownVar;
undefinedVar = anyVar;
neverVar = anyVar; //오류
}
anyVar = unknownVar;
같은 경우 되면 안된다. 왜냐면 unknown이 더 상위인데 any를 받는 다운캐스팅이니까, 근데 된다..!undefinedVar = anyVar;
도 계층도를 보면 되면 안된다. any가 더 상위인데 undefinedVar에 할당하는건 다운캐스팅이니까, 근데 또 된다...!type Book = {
name: string;
price: number;
}
type ProgrammingBook = {
name: string;
price: number;
skill: string;
}
let book : Book;
let programmingBook : ProgrammingBook = {
name : "한입",
price : 33000,
skill : "react",
}
book = programmingBook
programmingBook = book //오류
객체는 프로퍼티 개수가 더 적은게 상위 타입이다.
programmingBook = book
은 오류가 발생한다./**
* 초과 프로퍼티 검사
*/
let book2: Book = {
name: "한입",
price: 33000,
skill: "react", //오류 발생
};
let book3: Book = programmingBook
function func(book: Book) {}
func({ name: "한입", price: 33000, skill: "react" }); //skill 오류 발생
func(programmingBook);
func(programmingBook);
처럼 적던가, type에 정의된 프로퍼티만 써줘야 한다.이번엔 이런 상황을 보자.
객체 변수 person을 만드는데 초기값은 굳이 안넣고 빈 객체로 시작하고 싶다.
type Person = {
name: string;
age: number
}
let person = {}
person.name = '강' //에러 '{}' 형식에 'name' 속성이 없습니다.ts(2339)
person.age = 27; //에러 '{}' 형식에 'age' 속성이 없습니다.ts(2339)
type Person = {
name: string;
age: number
}
let person : Person= {} //에러 '{}' 형식에 'Person' 형식의 name, age 속성이 없습니다.ts(2739)
person.name = '강'
person.age = 27;
type Person = {
name: string;
age: number
}
let person= {} as Person //이렇게. 영어로는 type assertion
person.name = '강'
person.age = 27;
type Dog = {
name: string;
color: string;
};
let dog = {
name: "돌돌이",
color: "brown",
breed: "진도", //초과 프로퍼티
} as Dog;
이러한 타입단언은 만족해야 할 규칙이 하나 있는데 바로 A가 B의 슈퍼타입이거나, A가 B의 서브타입이어야한다는 것이다.
/**
* 타입 단언 규칙
* 값 as 단언 <- 단언식
* A가 B의 슈퍼타입이거나
* A가 B의 서브타입이어야함
*/
let num1 = 10 as never;
let num2 = 10 as unknown;
let num3 = 10 as string // 에러 'number' 형식을 'string' 형식으로 변환한 작업은
// 실수일 수 있습니다. 두 형식이 서로 충분히 겹치지 않기 때문입니다.
// 의도적으로 변환한 경우에는 먼저 'unknown'으로 식을 변환합니다.ts(2352)
let num3 = 10 as unknown as string; //다중 단언 -> 절대로 좋은 방법은 아님.
const 단언
/**
* const 단언
*/
let num4 = 10 as const;
let cat = {
name: "야옹쓰",
color: "yellow",
} as const;
cat.name = ""; //읽기 전용 속성이므로 'name'에 할당할 수 없습니다.ts(2540)
Non null 단언
!
를 줌으로써 타입스크립트에게, 아냐 이거 있어 ~! 라고 말해주는 것/**
* Non null 단언
*/
type Post = {
title : string;
author?: string;
}
let post : Post = {
title: '게시글1',
author: '정환쓰'
}
//'number | undefined' 형식은 'number' 형식에 할당할 수 없습니다.
// 'undefined' 형식은 'number' 형식에 할당할 수 없습니다.ts(2322)
// const len : number = post.author?.length;
const len: number = post.author!.length; //!를 줌으로써 non이나 null이 아님을 알려주는것
/**
* 타입 좁히기
* 조건문 등을 이용해 넓은타입에서 좁은타입으로
* 타입을 상황에 따라 좁히는 방법
*/
type Person = {
name: string;
age: number;
}
//value -> number : toFixed
//value -> string: toUpperCase
//value -> Date : getTime
//value -> Person : name은 age입니다.
function func(value: number | string | Date | null | Person) {
if (typeof value === "number") {
console.log(value.toFixed());
} else if (typeof value === "string") {
console.log(value.toUpperCase());
}
// else if (typeof value === 'object'){
// console.log(value.getTime())
// }
else if (value instanceof Date){ //왼쪽에 있는 value가 Date 객체니?
console.log(value.getTime());
} else if( value && 'age' in value){
console.log(`${value.name}은 ${value.age}입니다.`)
}
}
typeof value === ‘object'
로 처리하려 하면, 공포의 빨간줄이 그어진다. 왜냐면 매개변수에 null로도 받을 수 있는데, object가 null일 수 있기 때문이다.else if (typeof value === 'object'){
console.log(value.getTime()); // 오류 'value'은(는) 'null'일 수 있습니다.
}
instanceof
라는 타입 가드를 쓰게 되는데, 이건 쉽게 말해 왼쪽에 있는 value가 Date객체 맞니 ? 하는 것이다. else if (value instanceof Date){ //왼쪽에 있는 value가 Date 객체니?
console.log(value.getTime());
in
을 써주면 된다.else if( value && 'age' in value){
console.log(`${value.name}은 ${value.age}입니다.`)
}
value &&
을 붙였다는점이다. value라는 값이 있을 때, 를 붙여주지 않으면 value가 null일수도 있기에 빨간줄이 그어진다.서로소 유니온 타입도 함께 적으려 했는데 내용이 조금 있기도하고, 따로보면 더 좋을 것 같아 다음 글에 따로 작성해보려한다.