7장 코드를 작성하고 실행하기

ClassBinu·2024년 4월 28일

53 TS보다 ES 먼저

요약: js 초기 단점을 극복하기 위해 ts에 추가된 기능이 많은데 es가 발전하면서 js도 기능이 추가됨. 이게 충돌하는 경우 es가 우선인데 아직 남아 있는 것도 있음.

enum

ts 열거형은 상황에 따라 다르게 동작함.

  • 숫자 열거형에 0, 1, 2 외 다른 숫자가 할당되면 위험
  • 상수 열거형은 런타임에서 완전 제거됨
    (일반 enum은 런타임에도 존재함.)
// 상수 열거형
const enum Flaver {
  VALILLA = 0,
  CHOCHLATE = 1,
  STRAWBERRY = 2,
}

// 이 경우 컴파일러는 Flavor.CHOCLATE을 1으로 바꿔버림.

ts열거형은 js에서 동작이 다르다.
(함수 매개변수를 js에서는 문자열로 호출 가능하지만, ts에서는 enum을 import하고 호출해야 함)

결론: 문자열 열거형은 사용하지 않는 것이 좋음. 열거형 대신 리터럴 타입의 유니온 사용 권장

매개변수 속성

선호도는 있지만 간결한 문법임

// 일반 속성
class Person {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

// 매개변수 속성
class Person {
  constructor(public name: string) {}
}

import

놀랍게도 ES15 이전에는 JS 공식 모듈 시스템이 없었다.
그래서 각 환경마다 모듈 시스템이 존재했음.
node는 require, module.exports를 사용하고 AMD는 define 함수와 콜백을 사용함.

타입스크립트도 자체적인 모듈 시스템이 있었고, module 키워드와 '트리플 플래시' 임포트를 사용함.
이후 ES15가 공식적으로 모듈 시스템을 동입한 후, TS는 기존 module 기능을 하는 namespace 키워드를 추가함.

namespace foo {
  function bar() {}
}

/// <reference path="other.ts"/>
boo.bar();

근데 이건 호환성을 위해 남아 있는 것임. 이제 ES15로 스타일의 모듈을 쓰면 됨.(export, import)

데코레이터

클래스, 메서드, 속성에 어노테이션을 붙이거나 기능을 추가하는 데 사용

53 객체 순회 노하우

const obj = {
  one: "ooo",
  two: "ttt",
  three: "hhh",
};

for (const k in obj) {
  const v = obj[k];
}

교재에서는 이 코드가 편집기 에러가 난다고 하는데 실제로는 안 남

아, 옵션에 "noImplicitAny": true, 켜주니까 에러 발생함

타입 명시로 해결(임시 해결책)

const obj = {
  one: "ooo",
  two: "ttt",
  three: "hhh",
};

let k: keyof typeof obj;
for (k in obj) {
  const v = obj[k];
}

인덱스 시그니처로 해결

객체의 모든 속성이 같은 타입을 갖도록 명시적으로 선언하는 방법

interface StringDictionary {
  [key: string]: string;
}

const obj: StringDictionary = {
  one: "ooo",
  two: "ttt",
  three: "hhh",
}

for (const k in obj) {
  const v = obj[k];
}

Object.entries로 해결

const obj = {
  one: "ooo",
  two: "ttt",
  three: "hhh",
};

for (const [key, value] of Object.entries(obj)) {
  const v = value;
}

근데 entries는 ES2017부터 적용 가능

55 DOM 계층 이해

DOM 타입 활성화

{
  "compilerOptions": {
    "lib": ["dom", "es6"]
  }
}

DOM 타입 사용

function setElementText(elementId: string, text: string): void {
  const element = document.getElementById(elementId);
  if (element) {
    element.textContent = text;  // 'textContent'는 HTMLElement의 프로퍼티
  } else {
    console.log("Element not found");
  }
}

56 정보 은닉 목적으로 private 사용 금지

타입스크립트에서의 접근 제어자는 TS키워드이다. 즉, 컴파일 시에는 제거된다!
즉, TS의 접근 제어자는 컴파일 시에만 효력이 있고 언더스코어와 마찬가지로 런타임에는 효력이 없다!

그래서 타입스크립트에서 정보 은닉 목적으로 private을 쓰는 건 은닉 효과가 전혀 없다.

JS에서 정보 은닉을 위해서는 클로저를 사용하는 것!

declare function hash(text: string): number;

class PasswordChecker {
  checkPassword: (password: string) => boolean;
  constructor(passwordHash: number) {
    this.checkPassword = (password: string) => {
      return hash(password) === passwordHash;
    };
  }
}

const checker = new PasswordChecker(hash("password"));
checker.checkPassword("password");

passwordHash에는 어떤 일이 있어도 외부에서 접근 불가

클로저는 다시 추가 학습이 필요할 듯

클로저(Closure)는 함수와 그 함수가 선언된 렉시컬 환경(Lexical Environment)의 조합입니다. 함수가 생성될 때 그 함수 자체와 함께 그 함수가 선언된 시점에서의 변수들을 '캡처'하는 기능을 말합니다. 이렇게 캡처된 변수는 함수가 활성화되어 있을 동안 계속 유지되며, 외부 코드에서 직접적으로 접근할 수 없는 비공개 상태를 유지합니다.

이 개념은 함수가 자신이 선언됐을 때의 환경을 "닫아"두고, 이 환경에 포함된 변수에 계속 접근할 수 있도록 함으로써, 이후에 실행될 때도 그 환경에 접근할 수 있게 하는 기능을 말합니다.

가장 간단한 클로저 예시

function createCounter() {
    let count = 0; // 외부 함수의 지역 변수
    return function() {
        count += 1; // 내부 함수가 지역 변수를 참조하고 수정함
        return count;
    };
}

const counter = createCounter(); // counter는 클로저를 참조

console.log(counter()); // 1 출력
console.log(counter()); // 2 출력
console.log(counter()); // 3 출력

57 소스맵으로 TS 디버깅

ts가 js로 변환되면 원본가 다른 형태가 되어서 디버깅이 어렵다.
sourceMap 옵션을 true로 하면 .js 는 .js와 .js.map 두 개의 파일을 생성하고, .js.map이 소스맵이다.

소스맵이 .js와 같이 있으면 브라우저의 디버거에서 새로운 index.ts파일이 나타난다.
이게 있으면 생성된 js대신 ts를 소스로 사용할 수 있음.
그렇다고 진짜 .ts는 아님. 소스맵을 통해 ts처럼 보이는 것.

소스맵은 공개되지 않도록 주의

0개의 댓글