[TS] You Don't Know TS - 1. Type

devicii·2021년 10월 22일
0

typescript

목록 보기
1/1
post-thumbnail

1. What is TypeScript?

타입스크립트는 마이크로소프트(이하 MS)에서 구현한 JS의 슈퍼셋(Superset) 프로그래밍 언어이다.
확장자는 .ts이며 컴파일 결과물로 JS코드를 출력한다.
최종적으로는 이렇게 출력된 JS코드를 구동한다.

1-1. JS랑 TS의 다른 점이 뭐야? 🤷‍♂️

  • JS는 Dynamically typed의 언어이다.
    즉 프로그램이 동작할 때 실시간으로 타입이 결정돼서, 런타임 때 에러가 발생할 수 있는 문제점을 가지게 된다.
    또한 JS도 객체지향 프로그래밍이 가능하다. 프로토타입 기반으로 모두 구현할 수 있으나,
    다른 언어에 비해서 객체지향이 어려운 편이다.
    Class문법이 ES6에서 추가되기는 했지만 역부족이다.

  • TS는 위와 다르게 Statically Typed한 언어이다.
    기존의 c나 java와 같이 컴파일 시간에 타입이 결정돼서 컴파일 시간 때 에러를 잡을 수 있다.
    또한 TS는 타입의 추가와 더불어서 더 강력한 객체지향 프로그래밍을 할 수 있게 해준다.
    Class는 물론이거니와 generics, interface등을 지원한다.
    특징은 TS코드를 바로 적용할 수 없고 transCompile한 이후에 JS코드로 활용한다.
    컴파일은 자체 컴파일이나 바벨(Babel)을 활용한다.

1-2.Dynamically typed(동적 타입) VS Statically Typed(정적 타입)

동적 타입(JS)의 언어의 특징으로는 타입이 컴파일 시간이 아닌 런타임 시간에 변수에 어떤 것이 할당됐는지에 따라서 타입이 정해진다.

반대인 정적 타입(TS)의 특징은 타입을 명시해서 작성해야하고, 한 번 결정된 타입은 바뀔 수 없다.
다른 타입으로 할당하게 된다면 컴파일 시간에 에러를 만나볼 수 있다.

동적 타입 언어(TS)가 더 쉽고 유연하고 빠른 생산성을 가져서 초보자들에게 비교적 쉽다고 느낄 수 있지만, 타입이 없기 때문에 코드의 가독성이 떨어지며 에러를 잡기 어려운 면이 존재한다.
그에 비해 정적 타입 언어는 컴파일 과정에서 빠르게 에러를 잡을 수 있고 타입을 명시적으로 작성해야하기 때문에 코드 가독성이 좀 더 낫다. 또한 객체지향이 더 강력하다.(TS의 경우)

Example

//동적 타입 
let age = 10;
age = "young boy" (O)

//정적 타입
let age:number = 10;
age = "young boy" (X)

1-3.더 강력한 OOP(Object Oriented Programming)

TS는 JS보다 더 나은 OOP를 제공한다.

OOP는 현대 프로그래밍 언어에서 제일 보편적으로 사용되는 패러다임이다.
객체 위주로 모듈성 있는 코드를 작성할 수 있으며, 모듈별로 재사용할 수 있기 때문에 재사용성도 더 높고, 객체 단위로 확장해나갈 수 있기 떄문에 확장성도 높다. 기존 코드의 문제 해결이나 새로운 기능을 추가할 수 있는 유지보수성도 매우 높다.

아무래도 기존의 JS에서는 프로토타입을 기반으로 객체지향을 지원하고, ES6이후에 프로토타입을 베이스로 하는 Class문법이 추가됐지만 여전히 부족했다. 그러나 TS에서는 강력한 OOP를 제공한다. Generics, Interface, Class등 많은 문법을 제공한다.

2.Type

2-1. 추가된 타입

JS(ES6)의 경우에는 자료형은 number, string, boolean, null, nudefined, symbol와 같은 원시 자료형이 존재하고, 그 외에는 Object와 Funtion등이 있다.

TS에서 추가된 자료형 선언법

// 1. number

 const num: number = 1

 // 2. string

 const str: string = 'hi'

 // 3. boolean
 const bool: boolean = true

 // 4. undefined 이렇게 optional로 설정해줄 수 있다.
 // 이와 같이 | 를 활용해 더 다양한 자료형을 선언할 수 있다.

 let und: number | undefined
 und = undefined
 und = 2
	
  // 5. null 위와 같이 optional로 자주 활용한다.

 let nul: string | null

 // 6. unknown 가능하면 쓰지 않는 것이 좋다. 너무 추상적이기 때문이다. 자바스크립트와의 호환성 때문에 가끔 사용할 수는 있다.
 let notSure: unknown = 0
 notSure = 'test'
 notSure = 5

 //  7. any 똑같이 사용하지 않는 것이 좋다. bullshit.
 let anycall: any = 0
 anycall = 'rt'
 anycall = true

 // 8 void 함수의 리턴값이 없을 때 사용.
 function print(): void {
   console.log('hi world')
   return
 }
 let unusable: void = undefined 

 // 9. never 아무것도 리턴하지 않을 때 사용하는 타입이다.
 function throwErr(message: string): never {
   throw new Error(message)
 }

 // 9 object 명시적이지 못해서 이것도 딱히 좋은 방법은 아니다.
 let obj: object
 function accSomeObj(obj: object) {
   accSomeObj({ name: 'devicii' })
   accSomeObj({ gender: 'devicii' })
 }

2-2 함수에서 사용하는 방법

 // JS Style 기존의 JS문법
 function jsAdd(n1, n2) {
   return n1 + n2
 }

 function jsFetchNum(id) {
   //code ...
   //code ...
   //code ...
   return new Promise((resolve, rejects) => {
     resolve(100)
   })
 }
 // TS Style TS스타일의 문법
 function add(n1: number, n2: number): number {
   return n1 + n2
 }

 function TSFetchNum(id: string): Promise<number> {
   //code ...
   //code ...
   //code ...
   return new Promise((resolve, rejects) => {
     resolve(100)
   })
 }
 
  // 1.optional parameter

 function printName(firstName: string, lastName?: string) {
   //lastName에는 ?를 붙임으로서 붙여도 되고, 안붙여도 되는지를 설정해줌
   console.log(firstName) 
   console.log(lastName)
 }
 printName('devicii', 'jung')
 printName('devicii') //인자가 1개라서 불가능함. 상단의 optional ?를 넣어서 lastName이 들어가지 않아도 사용가능.

 //2. default parameter
 function printMessages(messages: string = 'default messages') {
   //이렇게 아무것도 인자값이 없다면 default의 값이 나온다.
   console.log(messages)
 }
 printMessages()

 //3. Rest parameter

 function addNumbers(...num: number[]): number {
   return num.reduce((a, b) => a + b)
 }
 console.log(addNumbers(1, 2))
 console.log(addNumbers(1, 2, 3, 4, 5))
 console.log(addNumbers(1, 2, 3, 4, 5))
 //이 함수는 누산기와 같은 역할을 하는 함수이다. 결과도 인자의 값이 모두 더해져서 나온다.

3. 배열과 튜플


 // Araay

 const friuts: string[] = ['🎃', '👭']
 const scores: Array<number> = [1, 3, 4]

 function printArr(friuts: readonly string[]) {
   // readonly를 붙여놔서 수정 생성이 불가능해진다.
 }

 // Tuple 서로 다른 타입의 데이터를 담을 수 있음. 튜플의 사용을 권장하지 않음.
 // Tuple 보단 interface, class, type alias등을 사용하는 것이 낫다.
 
 let studnet: [string, number]
 studnet = ['name', 1234]
 studnet[0] // name 출력
 studnet[1] // 1234 출력
 

4. Alias & Union and Intersection

4-1. Type Alias

Type Aliases를 활용해 새로운 타입을 정할 수 있다.

 type Text = string
 const name: Text = 'Devicii'
 const address: Text = 'korea'

 type Num = number
 type Student = {
   name: string
   age: number
 }
 // obj도 타입을 만들 수 있다.
 const student: Student = {
   name: 'deviicii',
   age: 24,
 }

 // String Literal Types

 type Name = 'devicii'
 let deviciiName: Name
 deviciiName = 'devicii'

 type JSON = 'json'
 const josn: JSON = 'json'

 type Boal = true
 let test: Boal = true

4-2. Union

Union types는 OR이라고 생각하면 편하다.

 type Direction = 'left' | 'right' | 'top' | 'bottom'
 function move(direction: Direction) {
   console.log(direction)
 }
 move('bottom')
 move('left')

 //한 개의 union만 사용 가능
 type TileSize = 8 | 12 | 16
 const tile: TileSize = 16

Union을 활용해 좋은 코드 작성하기

 type SuccessState = {
   result: 'success'
   res: {
     body: string
   }
 }
 type FailState = {
   result: 'fail'

   reason: string
 }
 
 1. 이렇게 두 개의 type을 loginState라는 한 개의 type으로 설정해준다.
 type LoginState = SuccessState | FailState

 function login(): LoginState {
   return {
     result: 'success',
     res: {
       body: 'logged in !',
     },
   }
 }
	2. 그리고 SuccessState와 FailState에 둘 다 result를 넣어준다면 이렇게 쉽게 조건문을 설정할 수 있다.
 function printLoginState(state: LoginState) {
   if (state.result === 'success') {
     console.log(state.res.body)
   } else {
     console.log(state.reason)
   }
 }

4-3. Intersection

Intersecion type is like & !


 type Student = {
   name: string
   score: string
 }

 type Worker = {
   employeeId: number
   work: () => void
 }
 
 //이렇게 internWorker라는 함수를 만드려면 &를 활용해서 두 타입의 속성을 활용할 수 있다.
 function internWorker(person: Student & Worker) {
   console.log(person.name, person.employeeId, person.work())
 }
 

5. Enum & Type Inference

5-1. Enum

enum은 열거형 변수로 정수를 하나로 합칠 때 편리한 기능입니다. 임의의 숫자나 문자열을 할당할 수 있으며 하나의 유형으로 사용해서 버그를 줄일 수 있습니다. (Line 개발팀 블로그 발췌)

 // JS에서는 Enum이 없어서 이렇게 Obejct의 freeze함수를 사용해 임의로 구현해주는 수밖에 없었다.
 const MAX_NUM = 6
 const MAX_STUDENTS_PER_CLASS = 10
 const DAYS_ENUM = Object.freeze({ MON: 0, TUE: 2 })
 const dayOfToday = DAYS_ENUM.MON

 // TS Enum
 
 // 그러나 TS에서는 Enum을 활용할 수 있어서 Days라는 Enum을 만들어 쉽게 구현이 가능해졌다.
 enum Days {
   Mon, // 0
   Tue, // 1
   Wed, // 2
   Thur, // 3
   Fri, //4
 }

 //변경가능
 그러나 Enum의 단점은 이렇게 새로운 깂을 힐딩해준디면 값이 바뀌게 된다.
 
 console.log(Days.Mon) //0
 let day: Days = Days.Tue
 day = Days.Thur
 day = 10

 // type으로 쓰면 리터럴 때문에 타입 안정성이 up!그러므로 enum보다 낫다 ...
 // 모바일 플랫폼이 아닌 경우엔 Enum보다 type을 쓰는 것을 적극 권장한다는 이유가 주류이다.
 type DaysOfWeek = 'Mon' | 'Tue' | 'Wed'
 let dayOfWeek: DaysOfWeek = 'Mon'
 dayOfWeek = 'deviii' // 불가능 하다고 ide에서 알려준다.

5-2. Type Inference

타입스크립트는 타입 추론을 지원한다. 프로그래머가 타입 표기를 적지 않아도 변수 및 값의 타입을 추론한다. 개똑똑하다.

  //   자동적으로 text는 문자열로 인식해서 1로 넣으면 에러가 뜬다.
  let text = 'hello'
  text = 1 //error !

  //string으로 message를 선언하지 않으면 any라서 웬만해서 string이라고 명시적으로 하는 것이 좋다.
  
  function print(message: string) {
    console.log(message)
  }

  //이런 함수에서 타입 추론은 웬만해서 지양하자. 명시적으로 반환형을 넣어주는 것이 좋다.
  // bad case 😕
  function add(x: number, y: number) {
    return x + y
  }
  const res = add(1, 3)

  // like this 😎
  function addFix(x: number, y: number): number {
    return x + y
  }
profile
Life is a long journey. But code Should be short :)

0개의 댓글