12 minute read

1. 오리엔테이션

1.1 정의

-. 캡틴 판교의 인프런 강의를 기반으로 학습 자료를 정리

2. 소개 와 배경

2.1 타입 스크립트란?

  • 타입스크립트 공식 문서
  • 타입스크립트는 자바스크립트의 슈퍼셋(타입을 부여) 언어입니다. 자바스크립트의 확장된 언어.
  • 타입스크립트는 브라우저에서 실행하려면 파일을 컴파일(complile) 하여야 함.

3. 시작하기

3.1 환경 준비

3.2 타입스크립트를 사용해야 하는 이유

  • 개발 단계에서의 문법 및 타입(형) 에러의 사전 방지
    • sample code
    // Jsdoc 문법을 사용하여 함수의 스펙 정의
    /**
    * @typedef {object} Address
    * @property {string} street
    */
    
    /**
    * @typedef {object} User
    * @property {string} name
    * @property {string} email
    * @property {string} address
    */
    
    /**
    * @returns {Promise<User>}
    */
    function fetchUser() {
        return axios.get(url);
    }
    fetchUser().then(function(response) {
        console.log(response.address.city); // address에 city가 정의되지 않았다고 소스단에서 확인 가능
    });
    
  • 코드 가이드 및 자동 완성(Intellisense)
    • sample code
      // 하기와 같은 경우 sum() 함수에 대해서 a:any, b:any와 같이 형이 없다
      function sum(a, b) {
      return a + b;
      }
      sum(10, 20);
      
      // typescript
      function add(a: number, b: number): number {
      return a + b;
      }
      add(10, '20');//와 같이 문자열로 지정시 파라메터의 형(type)이 맞지 않아 코드레벨에서 오류 확인
      add(10, 20);//정상적인 타입(형)을 사용
      

3.3 JavaScript를 TypeScript처럼 사용하는 방법

  • jsDoc를 사용하여 파라메터에 대해서 정의하고 //@ts-check 구문으로 TypeScript 구문 오류 확인
// @ts-check
/**
 * @param {number} a 첫번째 숫자
 * @param {number} b 두번째 숫자
 * @returns {number}
 */
function sum(a, b) {
    return a + b;
}
var SumResult = sum(10, '20');//'20'에 붉은 라인이 생김

3.4 TypeScript 시작과 컴파일

4. 기초 - 변수와 함수 타입

4.1 변수와 함수에 대한 참고

4.2 const, let

// ES6에서 사용하던 변수 선언 방식
// let
// 한번 선언 후 다시 선언할 수 없음
let a = 10;
let a = 20; // Error 발생

// const
// 한번 할당한 값을 재할당 및 변경 할 수 없음
const a = 10;
a = 20; // Error 발생

4.3 String, Number, Boolean, Array, Tuple, Any, Void, Never

let str: string = 'Hello'; // string
let num: number = 14; // number
let isValid: boolean = false; // boolean
let arr: number[] = [1, 2, 3]; // array
let arr: Array<number> = [1, 2, 3]; // array[type]
let arr: Array<string> = ['one', 'two', 'tree']; // array[type]
let arr: [string, number] = ['one', 1]; // 배열의 길이 고정, 각 요소 타입 지정

enum A = { a = 2, b, c} // 특정 값(상수)들의 집합
let enumA: A = A.b; // b
let enumB: A = A[1]; // b
let enumC: A = A[2]; // a 반환
let enumD: A = A[4]; // c 반환

// Any : 기존의 javascript -> typescript로 migration시 가장 많이 사용
// 모든 타입을 의미 한다.
let str: any = 'Hello';
let str: any = 15;
let arr: any = ['a', 2, true];

// Never : 함수의 끝에 절대로 도달하지 않는다 (무한 루프)
function neverEnd() : never {
    while(true) {}
}

4.4 블럭의 유효 범위

  • var의 유효 범위는 함수의 블럭 단위
  • for 반복문에서의 var 유효 범위 (반복문의 변수명에 따라 다름)
    • let을 통하여 해결
      var a = 10;
      for (var a = 0; a < 5; a++) {
          console.log(a); // 0 1 2 3 4 5
      }
      console.log(a); // 6
      
      var a = 10;
      for (let a = 0; a < 5; a++) {
          console.log(a); // 0 1 2 3 4 5
      }
      console.log(a); // 10
      

4.5 함수 및 파라메터(옵셔널)

function sum(a: number, b: number): number {
    return a + b;
}
sum(10, 20, 30, 40);//30, 40 파라메터로 Error

function sum(a: number, b?: number): number {
    return a + b;
}
sum(10);
sum(10, 20);

5. 1st 프로젝트 - To do Application

  • npm i 명령어를 사용하여 package.json 참고하여 install
  • typing : 타입이 정의되지 않은 코드에 타입을 정의해 주는 작업
    • 기존의 javascript에 typescript를 반영하기 위하여 많이 사용
  • index.ts 파일 참고
  • node를 활용하여 컴파일 및 실행
    $ node *.js
    

6. Interface

  • 서로간의 규칙을 정의한 것.
    • 객체의 속성, 타입 정의
    • 함수의 파라메터
    • 함수의 스펙
    • 배열과 객체의 접근 방식 정의
    • 클래스

6.1 함수의 인자(Parameter) 정의

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

var Hong: User = {
    age: 40,
    name: '홍길동',
};

function getUser(user: User) {
    console.log(user);
};

6.2 함수의 구조(Structure) 정의

// 함수의 구조 정의
interface SumFunction {
    (a: number, b: number): number
}
var sum: SumFunction;
sum = function(a: number, b: number): number {
    return a + b;
}
console.log(sum(1,2));

6.3 배열과 객체 접근

interface StringArray {
    [index: number]: string;
}
var arr: StringArray = ['a', 'b', 'c'];
arr[0] = '10';
console.log(arr);

6.4 딕셔너리(Dictionay) 정의

interface StringRegexDictionary {
    [key: string]: RegExp;
}
var obj: StringRegexDictionary = {
    // sth: /abc/
    cssFile: /\.css$/, //css 확장자를 가지는 모든 파일
    jsFile: /\.js$/, //js 확장자를 가지는 모든 파일
};
// obj['cssFile'] = 'a'; //인터페이스에 위배하였음으로 오류 발생
Object.keys(obj).forEach(function(value) {
    
});

6.5 확장(상속)

interface Person {
    name: string;
    age: number;
}
interface Developer extends Person {
    language: string;
}
var Hong1: Developer = {
    name: '홍길동',
    age: 100,
    language: 'Vue'
}
console.log(Hong1);

7. 타입 별칭

  • 좋은 소프트웨어는 확장이 용이해야 한다는 원칙
  • type 키워드를 사용하여 별칭으로 사용 가능하다. 단 type으로 선언하면 확장(상속)이 불가능
  • type확장성이 용이하지 않음으로 반드시 인지하고 사용해야 함
    type MyString = string;
    var str: MyString = 'hello';
    
  • Interface Sample
  • Type Sample

8. 연산자를 이용한 타입 정의

8.1 Union Type

  • 변수 또는 함수 매개 변수에 둘 이상의 데이터 형식을 사용
      function logMessage(value: string | number) {
      if(typeof value == 'string') {
          console.log(value.toString());
      }
     if(typeof value == 'number') {
          console.log(value.toLocaleString());
      }
      }
      logMessage('HELLO');
      logMessage(100);
    
  • 두개 이상의 공통된 속성만 접근가능하며, 나머지는 타입가드 처리 필요
    interface Developer {
        name: string,
        skill: string,
    }
    interface Person {
        name: string,
        age: number,
    }
    function askSomeone(someone: Developer | Person) {
        someone.name = '공동적인 이름';
        someone.skill = ''; //오류 발생
    }
    askSomeone({name: '개발자', skill: 'c#'});//모두 정의할 필요 없음
    

8.2 Intersection Type

  • 여러타입을 합쳐서 사용하는 타입
    interface Developer {
        name: string,
        skill: string,
    }
    interface Person {
        name: string,
        age: number,
    }
    function askSomeone2(someone: Developer & Person) {
        someone.name = '';
        someone.skill = '';
        someone.age = 100;
    }
    askSomeone2({name: '개발자', skill: 'c#', age: 100});//모두 정의해야 함
    

8.3 Type Guard

  • 타입의 유효성 검사
  • 특정 타입으로 타입의 범위를 좁혀(필터링)나가는 과장
      function logMessage(value: string | number) {
      if(typeof value == 'string') {
          console.log(value.toString());
      }
     if(typeof value == 'number') {
          console.log(value.toLocaleString());
      }
     throw new TypeError('value는 숫자나 문자여야 합니다');
      }
    

9. Enum

9.1 Enum

  • 특정 값들의 집합 자료형
  • enum sample #1
    enum Shose {
      Nike,
      Adias,
    }
    var MyShose = Shose.Nike;
    console.log(MyShose); // '0'으로 출력
    
  • enum sample #2
    enum Shose1 {
      Nike = '나이키',
      Adidas = '아디다스',
    }
    var myShose = Shose1.Nike;
    console.log(myShose); // '나아키'로 출력
    

9.2 Enum 사용

enum Answer {
    Yes = 'Y',
    No = 'N',
}
function askQuestion(answer: Answer) {
    if(answer == Answer.Yes) {
        console.log(`answer : ${answer}`, 'YES');
    }
    if(answer == Answer.No) {
        console.log(`answer : ${answer}`, 'NO');
    }
}
// askQuestion('yes');
// askQuestion('예스');
askQuestion(Answer.Yes);

10. Class

10.1 Class 기본 문법 예제

class Person {
    constructor(name, age) {
        console.log('생성 완료');
        this.name = name;
        this.age = age;
    }
}
var hong = new Person('', 100);
console.log(hong);

10.2 프로토타입

  • 자기 자신의 인서턴스 또는 객체를 생성할때의 원형을 의미

10.3 Object MDN(Mozilla Developer Network)

  • Bult-in Javascript API 또는 Javascript Native API

10.4 Prototyp vs Class vs typescript

// 이전의 생성자 함수를 작성하는 코드 패턴
function Person(name, age) {
    this.name = name;
    this.age = age;
}
var captOld = new Person('홍길동', 100);

// ES6에서 클래스를 사용하는 코드 패턴
class Person {
    constructor(name, age) {
        console.log('생성 완료');
        this.name = name;
        this.age = age;
    }
}
var captNew = new Person('홍길동', 100);
// 7_class.ts 즉, 타입스크립트로 작성할 경우 형식에 대한 명확한 구현이 필요 함
class Person {
    private name: string;
    public age: number;
    readonly log: string;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
}
var hong = new Person('홍길동', 100);

11. Generic

11.1 Generic 이란?

  • C#, Java 등의 언어에서 재사용성이 높은 컴포넌트를 만들때 자주 사용하는 특징으로 중복 코드 작성을 최소화하여 여러가지 타입을 수용할 수 있도록 컴포넌트를 생성하기 위해서 사용한다.
// 기존의 함수 및 인자 사용
function logText(text) {
    console.log(text);
    return text;
}
logText(10);
logText('Hi');
logText(true);

// 제너릭 타입 사용
function logText<T>(text: T) {
    console.log(text);
    return text;
}
logText<string>('Hi');

11.2 Union Type으로 Generic Type 해결

  • Union Type으로 입력파라메터는 해결되나 string, number의 명시적 타입 오류 발생
    function logText(text: string | number) {
      console.log(text);
      return text;
    }
    const a = logText('a');
    a.split(''); // Error 발생
    logText(10);
    

11.3 Generic Sample #1

function logText<T>(text: T): T {
    console.log(text);
    return text;
}
const str = logText<string>('abc');
str.split('');
const login = logText<boolean>(true);

11.4 Generic Sample #2

// 인자값 정의
const emails: { value: string, selected: boolean }[] = [
  { value: 'naver.com', selected: true },
  { value: 'gmail.com', selected: false },
  { value: 'hanmail.net', selected: false },
];

const numberOfProducts: { value: number, selected: boolean }[] = [
  { value: 1, selected: true },
  { value: 2, selected: false },
  { value: 3, selected: false },
];

function createDropdownItem(item: {value: string, selected: boolean}) {
  const option = document.createElement('option');
  option.value = item.value.toString();
  option.innerText = item.value.toString();
  option.selected = item.selected;
  return option;
}

// NOTE: 이메일 드롭 다운 아이템 추가
emails.forEach(function (email) {
  const item = createDropdownItem(email);
  const selectTag = document.querySelector('#email-dropdown');
  selectTag.appendChild(item);
});
// interface 정의
interface Email {
  value: string;
  selected: boolean;
}
interface ProductNumber {
  value: number;
  selected: boolean;
}

const emails: Email[] = [
  { value: 'naver.com', selected: true },
  { value: 'gmail.com', selected: false },
  { value: 'hanmail.net', selected: false },
];
const numberOfProducts: ProductNumber[] = [
  { value: 1, selected: true },
  { value: 2, selected: false },
  { value: 3, selected: false },
];

function createDropdownItem(item: Email | ProductNumber) {
  const option = document.createElement('option');
  option.value = item.value.toString();
  option.innerText = item.value.toString();
  option.selected = item.selected;
  return option;
}
emails.forEach(function (email) {
  const item = createDropdownItem(email);
  const selectTag = document.querySelector('#email-dropdown');
  selectTag.appendChild(item);
});
numberOfProducts.forEach(function (product) {
  const item = createDropdownItem(product);
});

11.5 Generic of Interface Sample

interface DropDown {
    value: string;
    selected: boolean;
}
const obj: DropDown = { value: 'abc', selected: false };

interface DropDown<T> {
    value: T;
    selected: boolean;
}
const obj: DropDown<string> = { value: 'abc', selected: false };
const obj2: DropDown<number> = { value: 100, selected: true };

11.6 타입 제한

// 'text.length'에서 오류 발생 : 제너릭 타입의 명시적 타입을 알 수 없다.
function logTextLength<T>(text: T) {
    console.log(text.length);
    return text;
}
// []와 같이 배열을 사용하면 'length' 속성 사용 가능
function logTextLength<T>(text: T[]): T[] {
    console.log(text.length);
    return text;
}

11.7 정의된 타입으로 타입 제한

interface LengthType {
    length: number;
}
function logTextLength<T extends LengthType>(text: T) : T {
    text.length;
    return text;
}
logTextLength(10); // 오류 발생
logTextLength({ length: 10 });
logTextLength({ lengh: 5 }); // 오류 발생

11.8 keyof을 사용하여 제너릭 타입 제한

interface ShoppingItem {
    name: string;
    price: number;
    stock: number;
}
function getShoppingItemOption<T extends keyof ShoppingItem>(itemOption: T): T {
    return itemOption;
}
getShoppingItemOption(10); // Error 발생
getShoppingItemOption<string>('a'); // Error 발생
getShoppingItemOption("price");

12. 2nd 프로젝트 - Phonebook Application

  • address-book 프로젝트의 src/index.ts 파일을 ES6 문법을 적용하여 리팩토링
  • .eslintrc.js 파일 수정
    // '@typescript-eslint/no-explicit-any': 'off',
    // "@typescript-eslint/explicit-function-return-type": 'off',
    
  • tsconfig.json 파일 수정
    "noImplicitAny": true,
    "strict": true,
    "strictFunctionTypes": true,
    

12.1 동기 방식 vs 비동기 방식

  • 동기 방식 ```javascript function fetchItems(): string[] { let items = [‘a’, ‘b’, ‘c’]; return items; } let result = fetchItems(); console.log(result);
- 비동기 방식
```javascript
 function fetchItems1(): Promise<string[]> {
  let items: string[] = ['a', 'b', 'c'];
  return new Promise(function (resolve) {
    resolve(items);
  });
}
fetchItems1();

13. 타입 추론

  • 타입 추론
    • 타입스크립트가 코드를 해석해 나가는 방식
  • 타입 추론
  • ES6에서 타입 추론은 기본 파라메터, 리턴타입등을 자동으로 판단

13.1 일반적인 타입 추론

var a = '10';

function getB(b = 10) {
    var c = 'hi';
    return c+b;
}

13.2 인터페이스와 제너릭을 이용한 타입 추론

interface Dropdown<T> {
    value: T;
    title: string;
}
var shoppingItem: Dropdown<string> = {
    value: 'abc',
    title: 'hello',
}

13.3 복잡한 구조에서의 타입 추론

interface Dropdown<T> {
    value: T;
    title: string;
}

var shoppingItem: Dropdown<string> = {
    value: 'abc',
    title: 'hello',
}

var detailedItem: DetailedDropdown<number> = {
    title: 'title',
    description: 'description',
    value: 10,
    tag: 20,
}

13.4 Best Common Type 추론 방식

  • 몇 개의 표현식(코드)을 바탕으로 타입을 추론한다. 가장 근접한 타입을 추론한다.
    var arr = [1, 2, true, true, 'a'];
    

13.5 Typescript Language Server

14. 타입 단언

14.1 타입 단언(Type Assertion)

  • 컴파일러에게 타입에 대해서 더 명확하게 인지하고 있다는 키워드 as
var a;
a = 'hi';
a = 20;
var b = a as number;

let div = document.querySelector('div') as HTMLDivElement;
if (div) {
    div.innerText;
}

15. 타입 가드

15.1 타입 가드

  • 타입 단언(Type Assertion)으로 구현된 경우 타입 가드를 구현하는 패턴
// 타입 단언 패턴을 사용하여 구현
interface Developer {
    name: string;
    skill: string;
}
interface Person {
    name: string;
    age: number;
}

function introduce(): Developer | Person {
    return { name: 'Tony', age: 33, skill: 'c#' }
}

var tony = introduce();
console.log(tony);

if((tony as Developer).skill) {
    var skill = (tony as Developer).skill;
    console.log(skill);
} else if((tony as Person).age) {
    var age = (tony as Person).age;
    console.log(age);
}

// 타입 가드 패턴을 사용하여 구현
function isDeveloper(target: Developer | Person): target is Developer {
    return (target as Developer).skill != undefined;
}
if(isDeveloper(tony)) {
    console.log(tony.skill);
} else {
    console.log(tony.age);
}

16. 타입 호환

16.1 타입 호환

  • [타입 호환이란] (https://joshua1988.github.io/ts/guide/type-compatibility.html)
  • 타입 스크립트에서 속성이 더 많은 타입이 더 작은 타입을 포함하여 호환 된다

16.2 Interface, Class

interface Developrt {
    name: string;
    skill: string;
}
interface Person {
    name: string;
}
var developer: Developrt;
var person: Person;
developer = person; // Error 발생
person = developer;
interface Developrt {
    name: string;
    skill: string;
}
class Person {
    name: string;
    skill: string;
}
var developer: Developrt;
var person: Person;
developer = person;
person = developer;
developer = new Person();

16.3 Function, Generic

// 함수
var add = function(a: number) {
    // ...
}
var sum = function(a: number, b: number) {
    // ...
}
sum = add;
add = sum; // Error 발생

// 제너릭
interface Empty<T> {
    // ...
}
var empty1: Empty<string>;
var empty2: Empty<number>;
empty1 = empty2;
empty2 = empty1;

interface NotEmpty<T> {
    data: T;
}
var notempty1: NotEmpty<string>;
var notempty2: NotEmpty<number>;
notempty1 = notempty2; // string, number 타입 오류 발생
notempty2 = notempty1; // number, string 타입 오류 발생

17. 타입 모듈화

17.1 타입 모듈화

// types.ts
interface Todo {
    title: string;
    checked: boolean;
}

export {
    Todo
};
// app.ts
import { Todo } from './types';

var item: Todo = {
    title: '할일',
    checked: false,
}

18. 출처

Leave a comment