[TIL] 2022-06-23 / Day 69 (타입스크립트 기본 문법)

미음제

·

2022. 6. 23. 19:05

 

중간 프로젝트(SNS 만들기)가 끝나고 오랜만에 강의를 다시 듣게 되었다. 처음 접하게 된 타입스크립트에 대해 간략하게나마 정리를 했다. 프로젝트 회고도 곧 정리해서 작성할 계획이다.

 

오늘 배운 내용

 

타입스크립트

 

타입 + 자바스크립트. 타입이 적용된 자바스크립트이다.

 

장점

 

  1. 안정성
  2. 가독성

 

명시적으로 타입을 지정해 사용하기 때문에 안정성이 높아진다. 컴파일 단계에서 미리 오류를 감지할 수 있기 때문이다. 자바스크립트는 타입 없이 사용하기 때문에 높은 자유도가 있지만, 직접 실행해보고 테스트하기 전까지는 오류를 감지하기 어렵다. 타입을 명시적으로 지정했기 때문에 실수를 줄일 수 있다.

 

타입을 명시적으로 작성했기 때문에 타입을 보고 무엇인지 알아보기가 쉽다. 네이밍만으로 유추하기 힘들다거나 다른 사람이 작성한 코드에서 정확하게 무엇인지 파악하기 쉽다고 생각된다.

 

단점

 

  1. 초기 설정을 해야 한다.
  2. 스크립트 언어의 유연성이 낮아진다.
  3. 컴파일 시간이 길어질 수 있다.

 

타입스크립트는 자바스크립트가 실행되는 브라우저에서 인식하지 못하기 때문에 컴파일이 필요하다. 이와 관련된 여러 세팅이 있는데 아직 직접적인 사용을 해보진 않아 잘 모르는 부분이다. 프로젝트를 진행하며 초기 세팅이 굉장히 까다롭다는 것을 알게된 만큼, 타입스크립트 세팅을 하면 세세히 기록해야 할 듯하다.

 

자바스크립트의 경우 변수 타입을 따로 지정하지 않는다. number 타입의 변수로 사용하다 string 타입의 변수로 자연스럽게 넘어갈 수 있고, 키워드 없이 작성하기 때문에 유연하다고 할 수 있다. 그러나 타입스크립트의 경우 타입이 강제되기 때문에 스크립트 언어 특유의 유연성이 없어질 수 있다.

 

애플리케이션이 커지면 커질수록 컴파일 시간이 길어질 수 있다. 아직 경험해보진 못했지만 별도의 컴파일을 거쳐야 하기 때문에 자연스러운 과정이라고 생각된다. 최근 진행했던 프로젝트도 마무리 단계에서 빌드 과정이 굉장히 오래 걸렸는데, 단점으로 꼽힐 정도라면 얼마나 느릴지..

 

타입스크립트 문법 1 : 타입 주석과 타입 추론

 

  1. 타입 주석 : 변수, 상수, 반환 값이 어떤 타입인지 명시하는 것
  2. 타입 추론 : 해당 변수가 어떤 타입인지 추론하는 것. 타입 주석을 생략하면 컴파일 시 어떤 타입인지 알아내고 나타낸다.

 

let a: number = 1; // 타입 주석
let b = 2; // 타입 추론, 타입 주석을 생략하더라도 추론하여 사용
b = 'a' // 타입 추론으로 넘버 타입이라는 것을 추론했기 때문에 스트링 타입은 사용할 수 없다.
let i: 1000 = 1000; // 특정 값을 타입으로 지정할 수 있다. 다른 값이 들어오면 X
let tmp: any = 3;
tmp = 'any' // any 타입은 자유로운 타입이다. any 타입의 사용은 지양, 유연성을 살리고자 할 때 사용

function add(a: number, b: number): number { // : number로 return 타입을 지정할 수 있다.
  return a + b;
}

 

 

b라는 변수에서 타입 추론을 통해 number 타입이 지정되었다. number 타입이 지정된 변수 b에 string 타입의 데이터를 입력하려 하니 생기는 오류 메시지이다.

 

let obj = { a: 1 };
obj.a = 3;
obj.b = 11; // { a: number } 형식에 'b' 속성이 없다.
obj.a = '3'; // 'string' 형식은 'number' 형식에 할당할 수 없다.

 

obj라는 변수에 a 속성이 담긴 객체를 지정했다. obj 객체의 a 속성은 number 타입으로 재할당이 가능하지만, 없는 속성 b 라던가, number 타입 속성 a에 string 타입을 지정할 수 없다.

 

타입스크립트 문법 2 : 인터페이스

 

객체 타입을 정의하는 방법으로 interface 키워드로 지정이 가능하다.

 

interface Cats {
  name: string;
  age?: number;
}

const HongSam:Cats = {
  name: '홍삼'
}

 

Cats라는 객체를 interface 키워드로 타입으로 정의하고, HongSam이라는 변수의 타입으로 Cats를 지정했다. name 속성은 string, age 속성은 number 타입이고, age 속성은 optional 한 값이다. 

 

재사용이 자주 되는 객체가 아니고 한 번만 사용되는 객체라면 익명 인터페이스로 정의하고 활용할 수 있다.

 

const HongSam: {
  name: string;
  age?: number;
} = {
  name: '홍삼',
  age: 4
}

 

타입스크립트 문법 3 : 튜플(tuple)

 

배열을 튜플(tuple)로 이용하는 방법이다. 타입스크립트에는 튜플이라는 명시적인 타입이 없다. 튜플은 고정된 길이를 갖는 배열을 의미한다. 

 

const cats: [string, number] = ['홍삼이', 4];
console.log(cats)
console.log(cats[0])
console.log(cats[1])

 

 

위와 같이 cats라는 변수에 튜플 타입(첫 번째 인자는 string 타입, 두 번째 인자는 number 타입)을 명시해주고 값을 '홍삼이'와 4를 입력했다.

 

입력된 튜플 타입에 맞지 않는 데이터를 입력하게 되면 오류가 발생하게 된다. 정확한 길이와 순서(순서에 따른 타입)을 지켜야 한다.

 

타입스크립트 문법 4 : enum

 

열거형을 사용하는 방법으로 임의의 숫자나 문자열을 할당할 수 있다.

 

enum Color {
  RED,  // 0
  GREEN, // 1
  BLUE, // 2
};

console.log(Color)
console.log(Color.BLUE)

 

 

커스텀한 데이터를 사용하지 않으면 순서대로 0부터 값이 매겨진다.

 

enum Color {
  RED = 'red',
  GREEN = 'green',
  BLUE = 'blue',
}; // 커스텀도 가능하다.

console.log(Color)
console.log(Color.BLUE)

 

 

커스텀 데이터를 입력하게 되면 해당 값을 갖게 된다.

 

타입스크립트 문법 5 : 대수 타입

 

여러 자료형의 값을 가질 수 있게 하는 방법으로 합집합, 교집합 타입이 있다.

 

let numOrStr: number | string;
numOrStr = 1;
numOrStr = 'str';

 

교집합 타입으로 지정하여 number 혹은 string 타입으로 지정했다. 따라서 numOrStr 변수에는 number 타입과 string 타입 데이터가 담길 수 있다.

 

let numAndStr: number & string = ''; // 합집합 타입은 원시 타입에서 사용할 수 없다.

 

합집합 타입은 교집합 타입과 달리 & 연산자를 이용해 지정한다. 원시형 데이터는 number 타입과 string 타입이 혼합된 데이터가 존재할 수 없으므로 원시형 데이터에서는 사용할 수 없다.

 

interface Name {
  name: string
}

interface Age {
  age: number;
}

let HongSam: Name & Age = { // 인터페이스에서 합집합 타입을 사용할 수 있다. | 도 가능
  name: '홍삼',
  age: 4
}

 

HongSam이라는 객체는 Name과 Age 인터페이스의 합집합 타입이다. 따라서 HongSam 객체는 name 속성과 age 속성을 모두 가져야 하고, name 속성은 string 타입을, age 속성은 number 타입을 가져야 한다.

 

interface Name {
  name: string
}

interface Age {
  age: number;
}

type Cat = Name & Age;

const HongSam: Cat = {
  name: '홍삼',
  age: 4
}

 

type 키워드를 통해 새로운 타입을 정의할 수도 있다. Name 인터페이스와 Age 인터페이스의 합집합 타입을 Cat이라는 새로운 타입으로 정의했다. 그리고 HongSam이라는 변수에 타입으로 Cat을 지정해 name 속성과 age 속성이 필요해졌고, 각각의 속성 타입도 따라야 한다.

 

타입스크립트 문법 6 : Optional

 

ES2021에도 추가된 기능으로, 타입스크립트에서는 이전부터 존재하던 기능이다. '?'를 붙여 해당 값이 없는 경우 undefined를 반환하게 된다. '!'가 붙는 경우 해당 값이 무조건 있다고 가정한다.

 

 

interface Post {
  title: string,
  content: string;
}
 
interface ResponseData {
  post?: Post;
  message?: string;
  status: number;
}

const response: ResponseData[] = [
  {
    post: {
      title: 'Hello',
      content: 'How r u?'
    },
    status: 200
  },
  {
    message: 'Error',
    status: 500
  }
];

console.log(response[0].post?.title); // post가 있는 경우 title 속성으로 접근, 없는 경우 undefined
console.log(response[1].post && response[1].post.title); // optional이 없을때 && 연산자로 검사를 진행했었다.
console.log(response[1].post?.title); // '?'가 붙어 있어 post가 없는 경우 undefined를 반환한다.
console.log(response[1].post!.title); // '!'가 붙어 있어 무조건 있다고 가정한다.

 

 

타입스크립트 문법 7 : Generic

 

하나의 인터페이스로 여러 타입을 이용할 수 있게 하는 방법이다. 이를 통해 인터페이스를 여러 번 만드는 것을 줄일 수 있다.

 

interface numberValue {
  value: number;
}

interface stringValue {
  value: string;
}

 

위처럼 Value 인터페이스를 number와 string에 따라 다르게 선언해야 하는 것과 달리 Generic은 한 번의 정의로 끝낼 수 있다.

 

interface Value<T> {
  value: T;
}

const numberValue: Value<number> = {
  value: 1
}

const stringValue: Value<string> = {
  value: 'string'
}

 

<T>를 통해 어떤 타입인지 지정할 수 있는 것이다.

 

타입스크립트 문법 8 : Partial, Required, Pick, Omit

 

각각의 키워드는 기존 인터페이스를 재활용할 수 있게 만들어 준다.

 

interface User {
  id: number;
  name: string;
  age: number;
  address: string;
  createdAt?: string;
  updatedAt?: string;
}

 

User라는 인터페이스가 위와 같다고 할 때 각각의 키워드는 다음과 같이 사용될 수 있다.

 

interface User {
  id: number;
  name: string;
  age: number;
  address: string;
  createdAt?: string;
  updatedAt?: string;
}

// 모든 필드가 Optional이 된다.
const partial: Partial<User> = {}

// 모든 필드가 Required가 된다. createdAt, updatedAt 속성이 없어 오류가 발생한다.
const required: Required<User> = {
  id: 1,
  name: 'MJ',
  age: 27,
  address: '경기도'
}

// 특정 필드만 골라서 사용할 수 있다.
const pick: Pick<User, 'name' | 'age'> = {
  name: 'MJ',
  age: 27
}

// 특정 필드만 빼고 사용할 수 잇다.
const omit: Omit<User, 'id' | 'createdAt' | 'updatedAt'> = {
  name: 'MJ',
  age: 27,
  address: '경기도'
}

 

  1. Partial : 모든 속성이 Optional이 된다.
  2. Required : 모든 속성이 Required가 된다.
  3. Pick : 원하는 속성만 가져다 사용할 수 있다.
  4. Omit : 원하지 않는 속성을 제거하고 사용할 수 있다.

 

타입스크립트 문법 9 : extends

 

특정 인터페이스를 상속받아 인터페이스를 확장한다. class extends와 비슷해 보인다. class를 사용해보지 않아서 잘 모르겠다..

 

interface Cats {
  name: string;
  age: number;
}

interface HongSam extends Cats {
  address: string;
}

const Hong: HongSam = {
  name: '홍삼이',
  age: 4,
  address: '경기도'
}

 

Hong이란 변수의 타입은 HongSam으로 address 속성이 string 타입으로 지정되어 있다. HongSam이라는 인터페이스는 Cats 인터페이스에서 extends 되었기 때문에 name 속성(string 타입)과 age 속성(number 타입)이 필요로 하다.

 


 

오늘의 회고

 

오래간만에 강의를 들으려니 집중이 안 되는 것 같다. 짧다면 짧고 길다면 긴 프로젝트 기간이 끝나고 긴장감이 풀려서 그런지 집중이 흐려진 것 같다. Vue 강의 이후 React 강의, 그리고 프로젝트 진행 후 타입스크립트 강의. Vue부터 지금까지 계속해서 새로운 내용들이다. Vue 강의 때처럼 강의도 밀리고 제대로 소화 히지 못하는 불미스러운 일이 생기지 않도록 집중해야 할 것 같은 느낌은 강하게 들지만.. 프로젝트가 끝났다 보니 조금 해이해진 것 같다. 주말까지 찬찬히 듣고 휴식도 취하고 다음 주부터 열심히 해야겠다.

 

타입스크립트를 써보지 않았고, 오늘 대략적인 강의만 듣게 되었는데 아직까지는 사람들이 왜 많이 찾는지, 얼마나 유용한지는 잘 모르겠다. 프로젝트 때 타입스크립트는 사용하지 않고 React PropTypes를 통해 타입 검사를 했는데, 그것 마저도 약간 번거로움이 있었고 유용성을 잘 느끼지 못했는데 타입스크립트도 그렇다. 추후에 강의를 더 듣고 적용해보면 알게 될지도? 우선 그전에 만들었던 컴포넌트를 타입스크립트로 작성해보라고 했으니 여러 번 시도해보고 천천히 느껴봐야 알 것 같다.

반응형