본문 바로가기

프로그래밍 공부내용/타입스크립트(TS)

타입스크립트 문제풀이 #1

 

 

포코에게 추천을 받은 타입스크립트 문제로 배우기..!

 

첫 예제이다


문제

  • Given the data, define the interface "User" and use it accordingly.

일단은 찬찬히 문제를 읽어보자.

 

object type unknown이라는 에러 메세지가 뜬다.

 

user라는 object의 type이 정해져 있지 않아서 생기는 문제같다.

 


내 문제 풀이

type을 정해주면 간단하게 해결 될 것 같았다.

 

다행히 어디를 손봐야 할지 문제에서 알려주었다. User를 정의하라고 한다.

export type User = {
    name:string,
    age:number,
    occupation:string,
};

export const users: User[] = [
    {
        name: 'Max Mustermann',
        age: 25,
        occupation: 'Chimney sweep'
    },
    {
        name: 'Kate Müller',
        age: 23,
        occupation: 'Astronaut'
    }
];

export function logPerson(user: User) {
    console.log(` - ${user.name}, ${user.age}`);
}

console.log('Users:');
users.forEach(logPerson);

아래와 같이 해결하였다.


해답 문제 풀이

export interface User {
    name: string;
    age: number;
    occupation: string;
}

export const users: User[] = [
    {
        name: 'Max Mustermann',
        age: 25,
        occupation: 'Chimney sweep'
    },
    {
        name: 'Kate Müller',
        age: 23,
        occupation: 'Astronaut'
    }
];

export function logPerson(user: User) {
    console.log(` - ${user.name}, ${user.age}`);
}

console.log('Users:');
users.forEach(logPerson);

 

interface로 만들어 주는 것을 놓쳤다.


해답에 대한 개념설명

- 타입스크립트 기본 문법

let helloWorld = "Hello World"; //let helloWorld: string

 

사실 타입스크립트는 자동으로 타입을 추론하는 능력을 어느정도 갖추고 있다.

 

하지만 타입 추론이 자동으로 하기 어려운 경우를 위해서 타입지정(defining types)를 지원해 준다.

 

이때, ' : ' 를 사용해서 어떤 타입을 가지는지 명시해준다. 

 

예시로 보면 간단하다.

interface User {
  name: string;
  id: number;
}
 
const user: User = {
  name: "Hayes",
  id: 0,
};

와 같은 방식으로 사용하고 타입을 직접 지정해 줬기 때문에, 타입체커가 더 세세하게 봐준다.

 

interface User {
  name: string;
  id: number;
}
 
const user: User = {
  username: "Hayes",
/*Type '{ username: string; id: number; }' is not assignable to type 'User'.
  Object literal may only specify known properties, and 'username' does not exist in type 'User'.*/
  id: 0,
};

 

 key에 username이 없다고 부리나케 알려준다!

 

 

- interface와 type의 차이

 

난 type으로 User를 정의했는데, 정답에서는 interface로 정의해서 두개의 차이가 궁금해졌다.

 

(이게 되네..? 지만 이유를 알고 가고 싶다.)

 

공식문서 핸드북 Object Types를 읽어보면 설명이 있는 것 같아서 찾아보았다.

 

공식문서에는

 

they can be anonymous, or they can be named by using either an interface, or a type alias.

 

라고 돼 있어서 별다른 힌트를 얻을 수 없었다.

 

하지만 개발자들은 극도의 귀차니스트다.

 

굳이굳이 두개가 같은데 넣어놨을리가 없다.

 

그래서 몇가지 정리된 글들을 찾아보다가 답을 찾았다!!!

 

 

interface는 선언병합 가능 /  type alias는 선언병합 불가능 이란다.

 

 

 

- 그래서 선언병합은 뭘까?

 

말 그대로 선언이 여러개일 때 같은 이름의 인터페이스를 알아서 합쳐준다는 뜻이다.

 

역시 말로는 어렵다. 예제로 보자

 

interface Box {
    height: number;
    width: number;
}

interface Box {
    scale: number;
}

let box: Box = {height: 5, width: 6, scale: 10};

box를 두개 선언했더니 알아서 합쳐줬다..!

 

 

 

- Type alias vs Interface

 

사실 본능적으로 공식문서의 예제들이 거의 interface를 쓰고 있기 때문에 나도 interface를  쓰고 잇었다.

 

'TypeScript 팀은 가능한 Type Alias보단 Interface를 사용하고, 합 타입 혹은 튜플 타입을 반드시 써야 되는

 

상황이 Type Alias를 사용하도록 권장하고 있습니다.'

 

나름 나의 야생성이 정답을 잘 찾아간듯 하다.

 

다만 합타입이나 튜플타입을 '반드시' 써야하면 type alias를 쓰라고 한다.

 

(결국 두개 다 알아야 된다는 소리..)

 

 

 

 

+추가. 합 타입은 뭔데요..? 알아야  쓰죠.

interface User {
    type: 'user';
    name: string;
    age: number;
    occupation: string;
}

interface Admin {
    type: 'admin';
    name: string;
    age: number;
    role: string;
}

export type Person = User | Admin;

export const persons: Person[] = [
    { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' },
    { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' },
    { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' },
    { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' }
];

나중에 볼 예제문제에서 발췌한 것이다. 

 

 

잘 보이나?

 

type Person = User | Admin;

 

으로 두개의 인터페이스를 '합' ~!! 타입으로 만들었다.

 


왜 이런걸 만들었을까?

 

- interface가 존재하는 이유?

 

객체의 속성에 대해서 정확히 어떤 값을 쓰는지 지정해주기 위해서 사용한 것 같다.

 

사실

const myWord :string;

정도는 선언을 해줘도 되고 안해줘도 되는 선택의 영역이다.(알아서 타입체커가 해주니까)

 

 

- 타입체커가 다 해주면 안돼? 해줘. 응애.

 

공부하다 보니까 불변성, 가변성과 엮어서 생각하면 맞는것 같다.

 

원시타입(불변성) 객체타입(가변성)
Number
String
Boolean
Null
Undefined
Symbol
Object
Array
Function

 

원시타입들은 잘 판단하고, 객체타입들은 지정을 해줘야하는 듯 하다.

 

원시타입은 수정시 새 주소에 새 값을 집어넣는다. 그래서 메모리상 어떤 값인지 쉽게 알 수 있다.

 

객체타입은 수정시 참조하는 주소값만 바꿔준다. 그래서 어떤 값인지 쉽게 알 수가 없다.

 

let a = { width:10 } 
let b = { width:10 }
console.log(a===b) // false

let c = a;
c.age = 5
console.log(a.width, c.width) // 5, 5 가 나온다. a도 바뀌어 버렸다.

또 위의 예제와 같이 값을 바꾸면 다른 변수들의 값도 바뀌기 때문에

 

규모가 커지면 어떤 녀석을 참조하고 있는지 알기가 쉽지 않고 위험성이 있다.

 

(자세히 알고 싶은 사람은 가변성, 불변성, 메모리 키워드로 공부해보자)

 

그래서 직접 명시를 해줘야만 하게 만든게 아닐까?

 

그게... 약속이니까..

 

 

 

- interface만 쓰면 안돼? type까지 하기엔 귀찮은데..

 

예제를 보니 '쓰임새가 좀 다르네...'  하고 느껴진다.

 

 

Type Alias으로 합병합 했더니 뭔가 상속과 비슷하게(동물 -> 기린, 사자, 거북이) 와 같이 쓸 수 있을 것 같고

 

Interface로 선언병합 한 것은 한가지 타입에 그때 그때 알아서 속성을 추가해주는 느낌이다.

 

두개가 쓰이는 상황이 달라서 두개 다 알아야 할것 같다.

 

 

 

 

 

 

이런걸로 아는 척 하고 다니면 좀 멋있으니까 알아놓자.

 

하라는데로 한건데요..?

 

라고 하는건 너무 하남자스럽다.

 


출처:https://typescript-exercises.github.io/#exercise=5&file=%2Findex.ts

 

TypeScript Exercises

A set of interactive TypeScript exercises

typescript-exercises.github.io

https://typescript-kr.github.io/

 

TypeScript 한글 문서

TypeScript 한글 번역 문서입니다

typescript-kr.github.io

https://medium.com/humanscape-tech/type-vs-interface-%EC%96%B8%EC%A0%9C-%EC%96%B4%EB%96%BB%EA%B2%8C-f36499b0de50

 

Type vs Interface, 언제 어떻게?

TypeScript에서 Type Alias와 Interface의 차이를 알아보기

medium.com