Jieunny의 블로그

Section 2. TypeScript 기본 & 기본 타입 본문

CodeStates/TS 스터디

Section 2. TypeScript 기본 & 기본 타입

Jieunny 2023. 2. 15. 11:17

📣  강의 내용 정리

𝟭.  Using Type

➰ number : 정수, 실수 상관없이 사용하는 숫자

➰ string : '', "", ``으로 사용하는 문자열

➰ boolean : truthy, falsy 값  

🚨 타입스크립트의 주요 원시 타입은 모두 소문자이다!

 

✔️ 타입 배정

➰ 타입을 추가하고자하는 변수에 ':' 을 추가하고 뒤에 타입 이름을 적어준다.

function add(n1: number, n2: number) {
    return n1 + n2;
}

const number1 = '5'; 	
const number2 = 2.8;

const result = add(number1, number2);
// 에러 (number1의 타입이 number가 아니기 때문)

타입스크립트는 컴파일을 차단하지 않고 실수에 대해 알려주기만 한다.

➰ app.js 파일에는 에러가 발생한 코드가 그대로 컴파일 된다.

 

𝟮.  TS 타입 vs JS 타입

✔️ JS 타입

➰ 동적 타입으로, 처음에 number를 할당했던 변수에 string을 할당할 수 있다.

➰ 분기를 사용해서 런타임에서 타입을 가져오는 경우가 있다.

if (typeof n1 !== 'number' || typeof n2 !== 'number) {
    ...
}

 

✔️ TS 타입

➰ 정적 타입으로, 처음에 number를 할당했던 변수에 string을 할당하면 에러가 발생한다.

➰ 변수가 어떤 타입을 보유할 수 있는지 여부를 명확히 해야 한다.

➰ 개발 도중에 타입을 가져온다.

 

𝟯.  타입 할당 및 타입 추론하기

// 타입 할당한 경우
function add(n1: number, n2: number, showResult: boolean, phrase: string) {
    ...
}

// 타입 할당 안 한 경우
const number1 = 5;
const number2 = 2.4;
const printResult = true;
const resultPhrase = 'Result is: ';

 

✔️ 왜 모든 변수에 타입을 할당하지 않는 것일까?

➰ 타입스크립트는 '타입 추론' 이라는 내장 기능을 활용하기 때문이다.

 number1, number2, printResult, resultPhrase의 경우 미리 어떤 값을 할당해주고 있다.

이 경우 타입스크립트가 그 값을 통해 타입을 완벽하게 추론할 수 있기 때문에 따로 타입 할당을 해주지 않는 게 좋다.

(타입 선언을 또 해줄 경우 반복되는 코드를 또 작성하는 것과 같다)

➰ 초깃값을 주지 않는 변수의 경우에는 타입 할당을 해줘서 나중에 그 변수에 어떤 값을 저장할 지 타입스크립트에게 알려주는 것이 좋다.

let str = 'hello' ;
str = 10;
// 에러 : 타입스크립트가 str을 string으로 추론했는데, number 값을 할당해줬기 때문이다.

 

𝟰.  객체 형태

✔️ 객체 타입

➰ 객체와 비슷하지만, 키-값 쌍이 아니라 키-타입 쌍을 작성해야 한다.

const person: {
    name: string;
    age: number;
} = {
    name: 'jieun',
    age: 30
};

➰ 객체 타입을 지정하는 예시일 뿐, 객체도 다른 타입과 마찬가지로 타입을 명시하는 것보다 타입스크립트가 추론할 수 있도록 하는게 좋다.

 

✔️ 중첩된 객체 및 타입

const product = {
  id: 'abc1',
  price: 12.99,
  tags: ['great-offer', 'hot-and-new'],
  details: {
    title: 'Red Carpet',
    description: 'A great carpet - almost brand-new!'
  }
}


// product 객체의 타입
{
  id: string;
  price: number;
  tags: string[];
  details: {
    title: string;
    description: string;
  }
}

➰ 객체 타입 안에 객체 타입이 있다.

 

𝟱.  배열 타입

let hobbies: string[];
// 문자열이 담긴 배열

for(const hobby of hobbies) {
    hobby.toUpperCase();
    hobby.map(()); // 에러

➰ hobbies를 문자열이 담긴 배열이라고 타입 선언 해줬기 때문에 타입스크립트는 이 배열에 담긴 요소들이 각각 string이란 것을 알고 있다.

➰ 때문에 문자열에는 없는 메서드인 map을 사용할 경우 에러를 발생시킨다.

 

𝟲.  튜플 타입(JS에는 없는 타입)

✔️ 튜플 : 길이와 타입이 고정된 배열 

let role: [number, string] = [2, 'author'];

role.push('admin');	// 성공
role[1] = 10;	// 에러
role = ['name', 1, 'string']	// 에러

➰ role에는 딱 두개의 요소만 있는 특수 배열을 입력해야 한다.

➰ 첫 번째 요소는 숫자여야하고, 두 번째 요소는 문자열 이어야 한다.

➰ push는 예외적으로 튜플에서 허용되기 때문에 타입스크립트가 에러로 잡아내진 못하지만, 적어도 잘못된 값을 할당하지는 못한다.

➰ 하지만 role를 다시 선언할 때는 딱 두개의 요소(첫번째 숫자, 두번째 문자열)를 가진 배열이어야 한다.

 

𝟳.  열거형으로 작업하기(Enum : JS에는 없는 타입)

✔️ Enum : 사용자 지정 타입

enum Role { ADMIN, READ_ONLY, AUTHOR };
Role.ADMIN // 0

➰ 값을 지정해주지 않으면 0부터 시작한다.

 

enum Role { ADMIN = 5, READ_ONLY, AUTHOR };
Role.AUTHOR // 7

➰ 값을 지정해주면 0, 1, 2 가 아닌 5, 6, 7 이 된다.

 

enum Role { ADMIN = 5, READ_ONLY = 'YES' , AUTHOR = 200};

➰ 혼합해서도 사용 가능하다.

 

𝟴.  Any 타입

✔️ Any : 모든 종류의 타입을 지정할 수 있다.

➰ 아주 유연하지만, 이 점이 타입스크립트의 장점을 모두 상쇄시키기 떄문에 가능한 사용하지 않는다.

➰ any를 사용하는 부분에는 타입스크립트 컴파일러가 작동하지 않는다.

 

𝟵.  유니언 타입

function combine(input1: number | string, input: number | string) {
    const result = input1 + input2;
    // 에러 : 타입스크립트는 여러 타입이 입력됬으니 '+' 연산자를 사용할 수 없는 타입도 있을 거라고 이해한다.
    return result;
}

➰ if 문을 사용해서 분기를 나눠주면 에러를 해결할 수 있다 -> 런타임 시 검사 필요

 

𝟭𝟬.  리터럴 타입

let result: 'as-number' | 'as-text';

➰ string 이나 숫자 등과 같은 핵심 타입을 기반으로 이 타입을 특정 목적으로 사용할 수 있다.

 

𝟭𝟭.  타입 알리어스 / 사용자 지정 타입

type Combine = number | string;

타입 알리어스는 '별칭' 으로 이해하면 된다.

새로운 이름으로 타입을 직접 생성할 수 있다.

유니언 타입을 활용해서 재사용 가능한 타입을 만들어낼 수 있다.

 

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

function greet(user: User) {
    console.log('Hi, I am' + user.name);
}

 객체 타입을 활용해서 재사용 가능한 타입을 만들어낼 수 있다.

 

𝟭𝟮.  함수 반환 타입 및 무효

✔️ 함수 반환

➰ 반환 타입도 변수와 마찬가지로 타입스크립트가 추론하게 하는 것이 좋다.

 

✔️ void 타입(JS에는 없는 타입)

function printResult(num: number): void{
    console.log('Result: ' + num);
}

➰ 아무것도 반환하지 않는다(반환문이 없다)

➰ 이 함수의 반환 값을 사용하면 undefined가 값으로 출력된다 !== undefined를 반환하는 것과는 다른 의미

➰ void : 반환문이 없다 / undefined : 값을 반환하지 않는 반환문이 있다

 

𝟭𝟯.  타입의 기능을 하는 함수

let combineValues: (a: number, b: number) => number;

➰ combineValues는 'number 타입의 매개변수 두개를 받고 number 타입을 반환하는 함수' 를 수용한다.

 

𝟭𝟰.  함수 타입 및 콜백

✔️ 함수 타입 

(a: number, b: number) => number

함수의 매개변수 및 반환 타입을 정의한다.

 

✔️ 콜백

function addAndHandle(n1: number, n2: number, cb: (num: number) => void) {
    const result = n1 + n2;
    cb(result);
}


addAndHandle(10, 20, (result) => {
    console.log(result);
    return result;
});

콜백 함수에 void를 사용해서 아무것도 반환되면 안된다고 명시했는데도 위 처럼 구현하면 콜백이 무언가를 반환한다.

'이는 아무것도 반환하지 않겠다' 는 뜻이 아니라 '반환할 수 있는 값이 사용되지 않도록 요구' 하는 것이다.

 

𝟭5.  unknown: 알 수 없는 타입

➰ 모든 값이 허용된다.

➰ 하지만 any와는 다르게 작동한다.

 

let userInput: unknown;
let userName: string;

userInput = 5;
userInput = 'Max';
userName = userInput; // 에러

➰ userInput에 'Max'를 지정한 것은 그 라인에 국한될 뿐이지 어떤 값이든 올 수 있기 때문에 에러가 발생한다.

➰ any 타입을 사용하면 에러가 발생하지 않는다.

➰ 이처럼 unknown 은 any보다 좀 더 제한적이다.

 

𝟭𝟲.  never: 절대 타입

function generateError(message: string, code: number): never {
   throw { message: message, errorCode: code };
}

➰ try catch를 사용하면 이 함수가 항상 스크립트나 그 일부와 충돌하기 때문에 아무것도 반환하지 않는다.

➰ 이런 함수의 반환 타입은 void 뿐만 아니라 never도 가능하다.

 


💡  새로 알게 된 내용

1. 타입스크립트 파일에서 에러가 나도 그 코드 그대로 컴파일해서 js 파일을 만들어낸다는 것

2. 왜 모든 변수에 타입 선언을 할당하지 않는지에 대한 구체적 이유

3. unknown, never 타입