Typescript

Rony·2021년 5월 24일
0

TypeScript는 Microsoft에서 개발하여 2012년에 발표한 JavaScript로 컴파일 되는 언어이다. JavaScript에 정적 타이핑과 ES2015를 기반으로 하는 객체지향적 문법이 추가된 것을 주요 특징으로 한다.

타입스크립트의 가이드는 다음의 페이지를 참고하도록 하자.

TypeScript 한글 문서

왜 써야하나?

타입스크립트를 사용하게 되면 다음과 같은 이점을 얻을 수 있다.

  • 잘못 된 타입 할당으로 인한 서비스 오류를 미연에 방지 할 수 있다.
  • 사용중인 변수에 들어가야 하는 값을 편하게 확인 할 수 있다.
  • 기존에 사용중인 javascript 코드에 영향을 주지않고 사용할 수 있다.

설치

테스트를 진행할 프로젝트를 생성해보자.

ts_test 라는 폴더를 만들고 해당 폴더를 vs_code 로 열어준다.

해당 프로젝트에서 yarn init -y를 입력하여 패키지를 생성한다.

다음의 모듈을 설치한다.

# 타입스크립트 모듈
yarn add typescript
# 타입스크립트를 콘솔에서 실행가능하게 해주는 모듈
yarn add ts-node

두개의 모듈 설치가 완료되었다면 다음의 명령어를 입력하여 타입스크립트 설정을 적용하자.

yarn run tsc --init

위의 명령이 적용되고 나면 tsconfig.json 파일이 생성되는데 여기서 타입스크립트의 설정을 적용할 수 있다.

이제 test.ts 파일을 생성한다.

( typescript 파일의 확장자는 .ts 로 생성한다. )

해당 파일에 각 타입별 변수 설정을 해보자.

타입설정

// 숫자 타입
const numbers: number = 100;

// 문자 타입
const strings: string = 'hello rony';

// trun or false
const YesOrNo: boolean = true;

// 숫자로 이루어진 배열
const lotte_number: number[] = [1, 15, 30, 31, 35, 36];

// 문자로 이루어진 배열
const dojae_students: string[] = ['chobby', 'sunny', 'kali', 'irving', 'karen'];

// enum
const color: 'red' | 'blue' | 'yellow' = 'blue';

// 정의되지 않은 속성값을 할당하는경우
const anyType = {
	[key: string]: string
}
// 또는
const anyType = {
	Record<string, string>
}

기존 자바스크립트와 똑같은데 차이점은 변수 옆에 :타입 을 지정해주었다는 점이다.

타입이 설정되었기 떄문에 설정한 타입과 다른타입의 값이 변수에 할당되면 에러가 표시된다.

Compile

yarn run tsc

위의 명령을 입력하게되면 test.js 파일이 생성되고 해당 파일에 들어가보면 우리가 기존에 작업했던 js 파일이 만들어진것을 확인할 수 있다.

이는 실제 배포시에는 브라우저에서 타입스크립트를 지원하지않을 수 있기 때문에 브라우저에서 인식가능한 js 파일로 컴파일해주는 작업이다.

이 과정에서 타입이 정상적으로 할당되지않았을때 빌드 실패가 발생되어 개발자는 어느부분에 문제가 있는지 손쉽게 파악 할수 가 있게 된다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c5413dbe-99b0-4c7e-ab73-bbbe17102d9e/Untitled.png

현재 별다른 설정을 하지 않았기 떄문에 루트 경로에 js 파일이 생성되지만 tsconfig.json 파일 수정을 통해서 .js 파일의 생성 경로를 지정해 줄 수 있다.

// tsconfig.json
{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */

    /* Basic Options */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
		"outDir": "./dist",                        /* Redirect output structure to the directory. */
    .....

tsconfig.json 의 outDir 의 주석을 해제 하고 폴더명을 입력해준 후 yarn run tsc 명령을 입력해주면

/dist/test.js 파일이 생성이 되는 부분이 확인된다.

생성된 js 파일은 var 변수를 사용하고 있는데 이는 target 가 es5 로 되어있어서 그렇기 때문에 이또한 es6 로 변경해주면 const, let 등을 사용하는 es6 문법이 적용되어 .js 파일이 생성된다.

그럼 생성된 코드의 실행은 어떻게 할까?

node test.ts 로 실행하게 되면 에러가 발생된다.

node 의 파일실행은 .js 파일만 가능하기 때문에 node 로 실행하기 위해서는 dist 에 컴파일한 .js 파일을 불러와서 실행을 해야 한다.

하지만 앞서 설치한 ts-node 를 사용하면 별도의 컴파일 작업없이 바로 ts 파일을 실행 할 수 있다.

yarn run ts-node test.ts

터미널에 출력값이 정상적으로 출력되는지 확인하자.

함수

함수를 사용시 타입 지정하는 방법을 알아보자.

함수의 경우 input 과 output 이 존재하기 떄문에 둘다 타입을 지정해 줄 수 있다.

function programmer (name: string): string {
  return name;
}

const user = programmer('rony');

// 또는 다음과 같이 함수 타입 정의
interface FuncType = {
	(name: string): string;
}

const user: FuncType = function programmer (name) {
  return name;
}

위와 같이 function 의 파라미터 옆에 input 타입을 설정할수 있으며 파라미터 괄호 뒤에 리턴 타입을 설정할 수 있다.

리턴타입을 설정했기 때문에 programmer 함수 호출값을 받는 user 는 string 타입으로 정의된다.

type, interface

객체인경우 타입선언을 어떻게 해줄수 있을까?

객체인경우에는 type 또는 interface 를 통해서 타입을 정의하고 정의된 타입을 변수에 할당하는 방식으로 타입지정이 이루어 진다.

// 타입을 먼저 선언하고 해당 타입의 값을 설정한다.
type RONY = {
  name: string;
  age: number;
  company: string;
  like_alcol: boolean;
};

// 변수선언시 설정한 타입을 할당한다.
const man: RONY = {
  name: 'rony',
  age: 39,
  company: 'playauto',
  like_alcol: true
};

위의경우 man 이라는 변수에 RONY 라는 타입을 할당했기 때문에 RONY 에서 선언된 필드가 무조건 들어가 있어야 한다.

하나의 값이라도 누락되는 경우에는 아래의 이미지와 같은 타입 에러가 발생된다.

내가 사용하려고 하는 변수에 특정 필드가 있을수도 있고 없을수도 있다면 타입선언시 ? 를 넣어주면 된다.

type RONY = {
  name: string;
  age: number;
  company: string;
  like_alcol?: boolean;
};

객체 타입을 type 로 정의하지않고 interface 로 정의하려면 다음과 같이 하면 된다.

interface RONY {
  name: string;
  age: number;
  company: string;
  like_alcol?: boolean;
};

인터페이스를 사용할경우의 장점은 클래스에 상속시켜서 사용할 수 있다는 것이다.

interface HUMAN {
  man(): {
    name: string;
    age: number;
    company: string;
    like_alcol?: boolean;
  },
  woman(): {
    name: string;
    age: number;
    company: string;
    like_alcol?: boolean;
  }
};

class Human implements HUMAN {
  man() {
    return {
      name: 'chobby',
      age: 19,
      company: 'playauto'
    }
  };
  woman() {
    return {
      name: 'sunny',
      age: 19,
      company: 'playauto'
    }
  };
};

위의 코드와 같이 함수를 가지고 있는 HUMAN 이라는 인터페이스를 Human 클래스에 상속하여 관련데이터를 처리할 수 있다.

인터페이스 확장

  • 여러개의 인터페이스를 합쳐서 사용할수도 있다.
interface Worker {
	name: '로니';
}
interface Person {
	age: 20
}

// worker + person + 새로운 타입을 추가한 인터페이스를 생성하려면..?
interface Programer extends Worker, Person {
	job: 'programer'
}

// Programer 은 다음과 같은 타입을 가지게 된다.
/*
interface Programer {
	name: '로니',
	age: 20,
	job: 'programer'
}
*/

// expends 를 통한 확장외에 &를 사용해서 하나로 합칠 수 있다.
type User = Worker & Person;

타입선언시 type 과 interface 중에 어떤걸 사용해도 상관없으니 일관성은 지켜야 한다고 하니 참고하자.

Generics

제네릭은 고정된 타입이 아닌 호출하는 타입이 어떤타입인지 알수 없을 때 사용한다.

보통 범용적으로 사용가능한 함수를 만들때 사용한게되는데, 사용법은 등으로 호출하여 쓴다.

( 굳이 T 를 쓰지않고 본인이 쓰고싶은 값을 넣어서 써도 된다. )

두개의 인자를 받아 배열로 리턴하는 함수가 있다고 한다.

문자열로 인자를 받는경우와 숫자형으로 인자를 받는경우가 있다고 할때 사용되는 타입이 다르기 때문에 처리로직이 동일함에도 각각의 함수를 생성해주어야 한다.

// 숫자를 인자로 받는경우
const sumArrNumber = (A: number, B: number): number[] => {
	const arr = [];
	
  arr.push(A);
  arr.push(B);

  return arr;
};

// 문지를 인자로 받는경우
const sumArrString = (A: string, B: string): string[] => {
	const arr = [];
	
  arr.push(A);
  arr.push(B);

  return arr;
};

위의 예제에서 sumArrNumber 과 sumArrString 은 처리로직은 같으나 파라미터의 타입과 리턴타입이 다르기 때문에 별도의 함수로 생성했다.

하지만 generic 를 사용할경우 하나의 함수로 처리가 가능하다.

// Generic 
const sumArr = <T1, T2>(A: T1, B: T2): (T1 | T2)[]  => {
  const arr = [];
	
  arr.push(A);
  arr.push(B);

  return arr;
};

// 숫자로 호출
const returnNumber = sumArr(1, 2);

//문자로 호출
const returnString = sumArr('work', 'life');

위와같이 제네릭을 사용하게 되면 호출하는 타입이 다르더라도 로직이 동일하면 하나의 함수로 처리가 가능하다.

-- END --

profile
sang kwon seo

0개의 댓글