[러닝 타입스크립트] Chapter 4 객체

해리포터·2023년 3월 6일
0
post-thumbnail

객체 타입 선언

객체 타입은 객체의 형태 를 설명하는 방법이다.

객체 타입과 객체 리터럴의 차이

  • 객체 타입
    • 타입을 사용해 설명
    • 변수 뒤에 콜론 : 을 사용하고 속성의 타입을 설명
    • 속성들을 세미콜론 ; 으로 구분
  • 객체 리터럴
    • 을 사용해 설명
    • 변수 뒤에 할당연산자 = 를 사용
    • 키-값을 콤마 , 로 구분
// 객체 타입
let friend: {
	name: string;
	age: number;
	hasJob: boolean;
}

// 객체 리터럴
friend = {
	name: "harry",
	age: 12,
	hasJob: true,
}

friend = "ron";
// Error: Type 'string' is not assignable to type '{ name: string; age: number, hasJob: boolean }'


별칭 객체 타입

객체 타입을 사용하는 것보다 타입 별칭(type alias)를 사용하는 것이 편리하다.

또한 오류 메세지가 보다 더 직관적이다.

type Person: {
	name: string;
	age: number;
	hasJob: boolean;
}

let friend: Person;

friend = {
	name: "harry",
	age: 12,
	hasJob: true,
}

friend = "ron";
// Error: Type 'string' is not assignable to 'Person'.


구조적 타이핑

  • 자바스크립트는 덕 타입(duck typed) 기반
  • 타입스크립트는 구조적 타입(structurally typed) 기반
type FullName = {
  firstName: string;
  lastName: string;
};

const hasBoth: FullName = {
  firstName: "Harry",
  lastName: "Potter",
};

const hasOnlyOne: FullName = {
  firstName: "Ron",
}

// Property 'lastName' is missing in type '{ firstName: string; }' but required in type 'FullName'.

객체 타입으로 명시한 변수에 값을 할당할 때, 그 값에는 객체 타입의 필수 속성들이 모두 포함되어야 한다.

객체 타입의 필수 속성들이 모두 명시되지 않은 값을 할당시키면 타입스크립트는 에러를 발생시킨다.

  • type FullName 에는 firstName, lastName 이 두 가지 필수 속성이 있다.
  • 변수 hasOnlyOne에 FullName 타입을 명시하려면 필수 속성인 firstName과 lastName 모두가 포함되어야 한다.
    • 필수 속성 외에 다른 속성(초과 속성)이 포함되어 있으면 안된다.
      type FullName = {
        firstName: string;
        lastName: string;
      };
      
      const hasBoth: FullName = {
        firstName: "Harry",
        lastName: "Potter",
      };
      
      const hasOnlyOne: FullName = {
        firstName: "Ron",
      	lastName: "Weasley",
        age: 30, // ❌
      }
      
      // Type '{ firstName: string; lastName: string; age: number; }' is not assignable to type 'FullName'.
      // Object literal may only specify known properties, and 'age' does not exist in type 'FullName'.
  • 변수 hasBoth는 type FullName과 구조적으로 일치하기 때문에 타입 에러가 발생하지 않는다.


중첩된 객체 타입

type Book = {
  author: {
    firstName: string;
    lastName: string;
  };
  title: string;
};

const HarryPotter: Book = {
  author: {
    firstName: "JK",
    lastName: "Rowling",
  },
  title: "Goblet of Fire",
};

const NoTitle: Book = { // ❌
  author: {
    firstName: "John",
    lastName: "Doe",
  }
}

// Property 'title' is missing in type '{ author: { firstName: string; lastName: string; }; }' but required in type 'Book'.

객체 타입의 속성 값이 객체 타입(중첩된 객체 타입)인 경우 type alias를 사용하면 코드의 가독성이 높아지고, 에러 메세지 또한 읽기 쉬워진다.

type Author = {
  firstName: string;
  lastName: string;
};

type Book = {
  author: Author; // ⭕️
  title: string;
};

const HarryPotter: Book = {
  author: {
    firstName: "JK",
    lastName: "Rowling",
  },
  title: "Goblet of Fire",
};

const NoTitle: Book = {
  author: { // ❌
    firstName: "John",
  }
}

// Property 'lastName' is missing in type '{ firstName: string; }' but required in type 'Author'.


Optional Property

타입의 속성 뒤에 ? 를 추가하면 옵셔널 프로퍼티로 나타낼 수 있다.

옵셔널 프로퍼티는 말 그대로 옵셔널(있어도 되고 없어도 되는)한 속성이다.

type Person = {
	name: string;
	age: number;
	job?: string;
};

const friend: Person = {
  name: "Harry",
  age: 20,
};

const enemy: Person = { // ❌
  age: 12,
  job: "Death Eaters",
}

// Property 'name' is missing in type '{ age: number; job: string; }' but required in type 'Person'.

만약 필수 속성의 타입이 undefined 인 경우, 반드시 해당 속성을 명시하고 값 또한 undefined라고 명시해야 한다.



명시된 객체 타입 유니언

잠재적으로 존재하지 않는 객체의 멤버에 대한 접근을 제한하면 코드의 안전을 지킬 수 있습니다.
(러닝 타입스크립트, p91)

있을 수도, 없을 수도 있는 속성을 제한하지 않으면 예기치 못한 에러가 발생할 수 있다.

객체 타입 유니언을 명시적으로 작성하면 이것에 대한 에러를 방지할 수 있다.

type Student = {
  name: string;
  school: string;
}

type Employee = {
  name: string;
  company: string;
}

type Person = Student | Employee;

const friend: Person = Math.random() > 0.5 
  ? { name: "Harry", school: "Hogwarts" }
  : { name: "Cornelius", company: "Ministry of Magic" };

friend.name; // ⭕️
friend.company; // ❌

// Property 'company' does not exist on type 'Person'.
// Property 'company' does not exist on type 'Student'.


객체 타입 내로잉

if (”속성” in 타입명시된변수)

type Student = {
  name: string;
  school: string;
}

type Employee = {
  name: string;
  company: string;
}

type Person = Student | Employee;

const friend: Person = Math.random() > 0.5 
  ? { name: "Harry", school: "Hogwarts" }
  : { name: "Cornelius", company: "Ministry of Magic" };

// 객체 타입 내로잉
if ("school" in friend) { // 여기서 school이 타입 가드의 역할을 한다.
  friend.school; // ⭕️
} else {
  friend.company; // ⭕️
}


교차 타입

유니언 타입이 or(|)의 개념이라면, 교차 타입은 and(&)의 개념이다.

여러 타입을 동시에 나타낸다.

여러 객체 타입을 합쳐서 하나의 type alias로 사용하는 것이 일반적인 교차타입이다.



never 타입

원시 타입은 결합될 수 없다. 따라서 각기 다른 원시 타입을 교차 타입으로 결합시키면 never 타입이 된다.

아주 특정한 상황이 아닌 이상 거의 사용되지 않는다.

type NotPossible = number & string; // never type
profile
FE Developer 매일 한 걸음씩!

0개의 댓글