記錄

TypeScript 요약 - 2 : 기본 타입 본문

FRONTEND STUDY/JavaScript

TypeScript 요약 - 2 : 기본 타입

prts 2022. 12. 18. 00:56

* Type Annotation

대상의 타입을 명시적으로 알려주는 것으로, 변수나 함수, 객체 속성명 뒤에 :type을 써서 데이터 타입을 지정할 수 있다. 이 Type annotation을 사용하여 type 검사를 수행한다. 필수사항은 아니라 타입을 직접 지정하지 않으면 타입스크립트가 타입을 추론해준다.

const val: number = 123
//변수 val의 type을 number로 지정해줌

원시 타입:: String, Number, Boolean

 

  • string(문자열) - JS에서 나타나는 문자열과 거의 동일하게 활용 가능(백틱을 이용한 표현식 등)
  • number(숫자)
  • boolean(true, false)
const str: string = 'STRING' //문자열
const num: number = 12345    //숫자
const bool: boolean = false  //불린

//BigInt
const big: bigint = 100n

원시값은 불변하는 값이며, 객체가 아닌 값들을 말한다. 이런 경우에는 타입 추론을 할 수 있기 때문에 따로 작성하지 않아도 무관하다.

 

원시값의 기본값 자체를 지정해 줄 수도 있다.

const str: 'string' = 'string' //소문자 string이여만 함
const num: 12345 = 12345    //숫자 12345 외 숫자가 들어가면 error 발생
const bool: true = true  //false가 들어가면 error 발생

null, undefined

const nu: null = null;
const un: undefined = undefined;

Javascript에서와 마찬가지로 null과 undefined를 고유의 특별한 타입으로 인정한다. 기본적으로 이 둘은 다른 모든 타입의 하위 타입이라 number 등의 타입에 할당할 수 있다. 모든 타입의 변수에 null과 undefined를 대입 가능하지만, 런타임에 예기치 않은 오류가 발생할 수 있기 때문에 보통 strictNullChecks 라는 옵션을 사용한다.

 

strictNullChecks 옵션을 사용하면 null 과 undefined는 오직 any와 각자 자신들 타입에만 할당 가능하다(예외: undefined는 void 에 할당 가능). null, undefined일 수 있는 변수를 참조하려고 하면 에러가 발생하기 때문에 일반적인 에러 방지에 도움이 된다.

function sayHello(word:string){
   if (word === 'world'){
      return 'hello' + word
   }
   return;
}
//declare function sayHello(word:string): string | undefined

function sayHi(word:string){
   if (word === 'world'){
      return 'Hi' + word
   }
   return null;
}
//declare function sayHi(word:string): string | null

사용할 때 혼란이 생길 수 있기 때문에 최대한 사용하지 않도록 주의하는 것이 좋으며, 규칙을 정해놓고 빈 값을 다룰 때 null 또는 undefined로 정해놓고 사용할 필요가 있다.

Symbol (ECMAScript 6 추가)

ES6에 추가된 기본 데이터 타입(원시 타입)으로, 변경 불가능한 유일한 값을 만들 수 있다. 만들 때마다 새로운 유일한 값을 만들 수 있다는 특징이 있다. (=내부 내용물이 같아 보여도 실제로 같은지 비교해보면 false를 출력함)

let sym1=Symbol()
let sym2=Symbol("text") //내부 텍스트는 symbol의 설명 역할 정도
let sym3=Symbol("text")

let sym=Symbol()
let obj={
  name:"kim",
  [sym]: 'value',
}

console.log(obj[sym])
//프로퍼티 키로 설정하면 키끼리 충돌하지 않게 됨(=중복 방지)

Object (객체)

object는 원시타입(number, string, boolean, bigint, symbol, null, undefined)이 아닌 타입을 나타낸다. object의 특성상 그대로 사용하면 any를 사용하는 것과 다름없는 상황이 될 수 있으므로, type의 범위를 좁힐 필요가 있다.

const obj:object={}  //X

const obj: { 
   str: string,
   num: number, inner: {
      str: string,
      num: number
   }}={
   str:'text',
   num: 1234567
   inner: {
      str:'script',
      num: 12345678
   }
}

console.log(obj.str) //"text"

class와 instance를 활용해서 다양한 형태로 작성할 수 있다.

instance(객체)는 class 를 통해서 생성한 실체로, new 연산자를 이용해 객체를 생성할 수 있다.

(클래스에 관한 부분은 추후에 정리)

// person.ts
class Person {
  // 클래스 프로퍼티를 사전 선언하여야 한다
  name: string;

  constructor(name: string) {
    // 클래스 프로퍼티수에 값을 할당
    this.name = name;
  }

  walk() {
    console.log(`${this.name} is walking.`);
  }
}

const person = new Person('Lee');
person.walk(); // Lee is walking

Function  함수 타입

함수 타입을 작성할 때는 매개변수와 반환할 값을 지정해줘야 한다. 반환값의 타입을 지정해주면 어느 정도 결과값의 타입을 추론할 수 있다.

function func(num: number, str: string): str{
   return num + str
}

func(123,'str')

반환값의 타입이 지정한 타입과 다르거나 매개변수의 타입이 다르게 작성되면 에러가 발생한다.

function func(num1:number, num2:number):string {
   return num1 + num2
}

func(123, 456)  
//반환값의 타입이 string으로 지정되어 있으나 실제 결과는 number 타입이기 때문에 에러 발생

매개변수로 객체를 받아서 사용할 수도 있다.

const func = (obj:{str1: string, str2: string}) => {
   return obj.str1 + ' ' + obj.str2
}

func({str1:'hello', str2:'world'}) //hello world

Array (배열)

기존에 우리가 알고 있는 배열과 크게 다르지 않지만, 자바스크립트에서 배열이 객체로 취급되는 타입이라는 것을 유의하고 작성하자.

타입스크립트에서 배열은 두 가지 방식으로 작성할 수 있다.

const array:string[]=['a','b','c'] 
const array1: Array<string>=['a','b','c']  //generic
//Array<string>으로 작성할때 반드시 대문자로 시작

const numArr:number[]=[1, 2, 3, 4, 5]
const numArr1: Array<number>=[6, 7, 8, 9, 10]

const boolArr: boolean[]=[true, false, false, true]

위와 같이 number[], boolean[] 등으로 배열 안에 들어갈 요소들의 타입을 작성하고, 그에 맞는 요소들이 들어간 배열을 작성해주면 된다. 타입에 맞지 않는 요소를 배열에 push하면 에러가 발생한다.

Tuple (튜플)

튜플 타입을 사용하면 요소의 타입과 개수(index)가 고정된 배열을 표현할 수 있다. 즉, 길이와 타입이 고정된 배열이라고 할 수 있다.  튜플을 사용하면 여러가지 타입으로 이루어진 배열을 안전하게 관리할 수 있다.

let user:[string,number,boolean]=['hello', 123,'false']
//declare let user: (string | number | boolean)[];

튜플 배열에 들어갈 타입을 괄호 안에 작성해주고, 작성한 순서와 개수대로 요소가 들어가야 한다. (=각 요소마다 타입을 지정한다)

 

배열 구조분해할당을 이용하면 배열 타입의 길이를 조절할 수 있다.

const tuple:[number, ...string[]] = [2, 'a', 'b', 'c']

Enum (열거)

enum은 enumeration의 약자로, 이름이 있는 상수들이 열거되어 있는 집합이다. 즉, 값의 집합에 이름을 붙여줄 수 있는 타입이다. 0부터 시작해 요소들의 번호를 매기고, 요소 중 하나의 값을 수동으로 설정함으로써 번호를 변경할 수 있다.

enum Color {
    Red,
    Green,
    Blue,
}
var col = Color.Red
col = 0 // Effectively same as Color.Red

enum은 0의 값을 기준으로 1씩 값이 자동으로 증가한다. 직접 값을 지정할 경우, 할당된 값을 기준으로 1씩 증가한다.

예를 들어, A=100, B=200 으로 설정하고 C, D의 값을 지정하지 않았을 시, C=201, D=202로 나온다.

enum Color {
    Red, // 0
    Green, // 1
    Blue, // 2
}

//값을 할당해 숫자 변경
enum Color {
    DarkRed = 3, // 3
    DarkGreen, // 4
    DarkBlue, // 5
}

any, void, never

  • any : 어떤 타입의 값이든 할당이 가능한 타입
  • void : 어떤 타입도 존재할 수 없는 타입
  • never : 어떠한 값도 가질 수 없는 타입(공집합의 개념으로 생각하면 됨)

any 타입은 모든 값(타입)의 집합이라고 할 수 있는, 어떤 타입의 값이든 할당이 가능한 타입이다. 실질적으로 일반적인 자바스크립트를 쓰는 것과 다를 바가 없어지고, 런타임에서 에러를 야기할 수 있으므로 사용하지 않는 것이 좋다.

noImplicitAny:true 또는 strict:true 를 설정하면 any 사용 시 에러가 발생되기 때문에 이러한 옵션들을 설정해 두는 것을 권장한다.

function func(anyParam) {}
//declare function func(anyParam:any):void;

//any를 사용하면 런타임에서 에러가 발생하는 메서드를 사용해도 에러가 발생하지 않음

void 타입은 어떤 타입도 존재할 수 없는 타입으로, 보통 함수에서 반환값이 없을 때 사용한다. Javascript에서는 암시적으로 undefined를 반환하지만, void와 undefined는 TypeScript에서 같은 것이 아닌 점을 유의해야 한다.

반환값이 없으면 타입스크립트에서 자동적으로 void로 타입 추론을 해주기 때문에 타입스크립트의 타입 추론에 맡기는 것을 추천한다.

function someFunc():void {
  console.log('hello')
}

never 타입은 어떠한 값도 가질 수 없는, 절대로 발생할 수 없는 타입이다. 예를 들어, 함수 표현식이나 화살표 함수 표현식에서 항상 오류를 발생시키기거나 절대 반환하지 않는 반환 타입으로 쓰인다.

never은 모든 타입에게 할당 가능한 하위 타입이지만, 어떤 타입도(any 포함) never에 할당할 수 있거나 하위 타입도 아니다(never 자신 제외).

let value:never
//아래 전부 에러남-말 그대로 값을 가질 수 없음
value=undefined
value=null
value='hello'
value=5

 

* void와 차이점 및 never 반환 예시
void 는 return 값이 없을 뿐이지 함수가 종료는 되지만, never은 함수가 종료될 수 없다.
함수에서 never은 무한루프를 돌거나(=함수가 종료되지 않을 때) 에러를 throw 할 때 사용한다.

//Error throw
const someFunc=(message: string):never=>{
  throw new Error(message);
}

//never 반환하는 함수는 종료되지 않음(=마지막에 도달할 수 없음)
const someFunc=():never=>{
   while (true) {}
}

// 반환 타입이 never로 추론됨
function fail() {
   return error("Something failed");
}

Unknown

unknown은 새로운 최상위 타입으로, 어떤 타입인지 알 수 없는 타입이다. any와 유사하게 어떤 값이든 들어올 수 있는 타입이지만 더 안전하게 사용이 가능하고 상대적으로 엄격하다. 타입을 특정해주기 전에는 작업을 수행하려고 하면 에러가 발생한다.(any는 함수의 정상 작동을 보장해주지 않아 런타임에서 에러 발생할 수 있음)

function func(x:unknown){
   let val1:any = x;
   let val2:unknown = x;
   let val3:string = x;
   let val4:boolean = x;
   let val5:number = x;
   let val6:string[] = x;
   let val7:{} = x;
}
//string, boolean, number, string[], {}은 동작하지 않음
//any와 unknown은 최상위 타입이기 때문에 동작

타입스크립트에서 타입을 unknown으로 추론하는 경우는 없기 때문에 개발자가 직접 명시해야 하며, unknown타입을 사용할 때는 Type assertion 혹은 타입 가드와 함께 사용한다.

 

타입 가드는 이 타입이 맞는지 검증하는 것으로, 예외처리를 할 때 활용할 수 있다.

//typeof a === "string"일때만 a.toUpperCase() 실행하도록 예외처리

function f2(a:unknown){
  if (typeof a==='string'){
    return a.toUpperCase()
  } else {
    return '문자열이 아닙니다'
  }
}

타입 표명(Type assertion)은 타입이 어떤 타입인지 강제하는 문법으로, 프로그래머가 컴파일러에게 자신이 타입에 대해 더 잘 알고 있다고 주장하는 것이다. 타입을 강제하는 기능이기 때문에 굳이 사용하지 않아도 된다.

let num: unknown = 99;

if (typeof num === 'string'){
   (num as string).trim();
}
//as foo 의 형식으로 타입 표명

//angle-bracket 문법이 있으나 JSX와 사용 시 문법적으로 모호해져 as 문법을 권장
//angle-bracket 예시

var foo: any;
var bar = <string> foo; // 이제 bar의 타입은 "문자열"입니다

참고자료

 

https://velog.io/@muz/TypeScript-%EA%B8%B0%EB%B3%B8-%ED%83%80%EC%9E%85

https://doitnow-man.tistory.com/entry/typescript-8-class-%EC%99%80-instance

https://radlohead.gitbook.io/typescript-deep-dive/type-system/type-assertion

 

 

'FRONTEND STUDY > JavaScript' 카테고리의 다른 글

[JS]Dark mode Toggle  (0) 2022.12.26
TypeScript 요약 - 1  (0) 2022.12.11
this  (0) 2022.12.04
Intl (internationalization) API  (0) 2022.11.27
Cookie, LocalStorage, SessionStorage  (0) 2022.11.20
Comments