Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions 7장-코드를 작성하고 실행하기/yeonjin/item53.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
## [ITEM 53] 타입스크립트 기능보다는 ECMAScript 기능을 사용하기

자바스크립트에 새로 추가된 기능과, 초기 타입스크립트가 독립적으로 개발했던 기능의 호환성 문제로 피해야할 몇가지 기능들

### 열거형(enum)

- 열거형은 상황에 따라 다르게 동작한다.
- 숫자 열거형에 0,1,2 외의 다른 숫자가 할당되면 위험하다.
- 상수 열거형은 보통의 열거형과 달리 런타임에서 완전히 제거된다.
- preserveConstEnums 플래그를 설정한 상태의 상수 열거형은 보통의 열거형처럼 상수 열거형 정보를 유지한다.
- 문자열 열거형은 명목적 타이핑을 사용한다. (타입의 이름이 같아야 할당 허용)
- 열거형 대신 리터럴 타입의 유니온을 사용한다.

```tsx
type Flavor = "vanilla" | "chocolate" | "strawberry";

let flavor: Flavor = "chocolate";
flavor = "mint chip"; //~~~~ "mint chip" 유형은 'Flavor' 유형에 할당할 수 없습니다.
```

### 매개변수 속성

- 아래 예시에서 public name은 매개변수 속성이다.

```tsx
class Person {
constructor(public name: string) {}
}
```

- 일반 속성

```tsx
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
}
```

- 일반 속성과 매개변수 속성 중 한 가지를 통일성 있게 사용하는 것이 좋다.

### 네임스페이스와 트리플 슬래시 임포트

- 타입스트립트 자체 모듈 시스템 → module 키워드, 트리플 슬래시 임포트
- ECMAScript 공식 모듈 시스템과 호환되기 위한 namespace 키워드 추가 (호환을 위함. 기본적으로는 import, export를 사용해야 함)

```tsx
namespace foo {
function bar() {}
}

/// <reference path="ohter.ts"/>
foo.bar();
```

### 데코레이터

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

```tsx
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@logged
greet() {
return "Hello, " + this.greeting;
}
}

function logged(target: any, name: string, descriptor: PropertyDescriptor) {
const fn = target[name];
descriptor.value = function () {
console.log(`Calling ${name}`);
return fn.apply(this, arguments);
};
}

console.log(new Greeter("Dave").greet());
// 출력:
// Calling greet
// Hello, Dave
```

- tsconfig.json에 experimentalDecorators 속성 추가
- 표준화 X → 데코레이터가 표준이 되기 전에는 타입스크립트에서 데코레이터를 사용하지 않는 게 좋다
29 changes: 29 additions & 0 deletions 7장-코드를 작성하고 실행하기/yeonjin/item54.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## [ITEM 54] 객체를 순회하는 노하우

### 타입 한정

- 키가 어떤 타입인지 정확히 파악하고 있다면 let k: keyof T와 for-in 루프를 사용한다.
- 함수의 매개변수로 쓰이는 객체에는 추가적인 키가 존재할 수 있다.

```tsx
function foo(abc, ABC) {
let k: keyof ABC; // 이 코드를 추가하지 않으면 다르게 추론될 수 있음
for (k in abc) {
// let k : "a" | "b" | "c"
const v = abc[k]; // string | number 타입
}
}
```

→ 타입이 너무 좁아 문제가 발생할 수 있음

### Object.entries 사용하기 (일반적인 방법)

```tsx
function foo(abc: ABC) {
for (const [k, v] of Object.entries(abc)) {
k; // string 타입
v; // any 타입
}
}
```
52 changes: 52 additions & 0 deletions 7장-코드를 작성하고 실행하기/yeonjin/item56.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
## [ITEM 56] 정보를 감추는 목적으로 private 사용하지 않기

- 자바스크립트는 클래스에 비공개 속성을 만들 수 없다.
- 비공식적으로 앞에 \_언더스코어를 붙여서 비공개 속성을 표현했다. (실제론 접근할 수 있음)
- ts의 public, protected, priavte 키워드는 컴파일 이후에 제거된다.
- 정보를 감추기 위해 private을 사용하면 안 된다.

### 클로저 사용하기

- 정보를 숨기기위한 방법
- 외부에서 passwordHash 변수에는 접근할 수 없다.
- passwordHash에 접근해야 하는 메서드는 생성자 내부에 정의되어야 한다.
- 메서드 정의가 생성자 내부에 존재하면 인스턴스를 생성할 때마다 각 메서드의 복사본이 생성되기 때문에 메모리를 낭비하게 된다는 것을 기억해야 한다.
- 동일한 클래스로부터 생성된 인스턴스라고 하더라도 서로의 비공개 데이터에 접근하는 것이 불가능하다. (일반적인 객체지향 언어에서는 클래스 단위 비공개이지만, 클로저 방식은 인스턴스 단위 비공개)

```tsx
declare function hash(text: string): number;

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

const checker = new PasswordChecker(hash("s3cret"));
checker.checkPassword("s3cret"); // 결과는 true
```

### 비공개 필드 기능(#) 사용하기

- 접두사로 #을 붙여서 타입 체크와 런타임 모두에서 비공개로 만든다.
- 클래스 메서드나 동일한 클래스의 개발 인스턴스끼리는 접근이 가능하다.

```tsx
class PasswordChecker {
#passwordHash: number;
constructor(passwordHash: number) {
this.#passwordHash = passwordHash;
{

checkPassword(password: string) {
return hash(password) === this.#passwordHash;
}
}

const checker = new PasswordChecker(hash('s3cret'));
checker.checkPassword('secret');
checler.checkPassword('s3cret');
```
3 changes: 3 additions & 0 deletions 7장-코드를 작성하고 실행하기/yeonjin/item57.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## [ITEM 57] 소스맵을 사용하여 타입스크립트 디버깅하기

- 소스맵은 자바스크립트로 변환된 코드의 위치와 심벌들을 원본 코드의 원래 위치와 심벌들로 매핑한다.
138 changes: 138 additions & 0 deletions 8장-타입스크립트로 마이그레이션하기/yeonjin/item58.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
## [ITEM 58] 모던자바스크립트로 작성하기

### ECMAScript 모듈 사용하기

```tsx
// a.ts
import * as b from "./b";
console.log(b.name);

// b.ts
export const name = "Module B";
```

### 프로토타입 대신 클래스 사용하기

- 프로토타입으로 구현한 Person 객체보다 클래스로 구현한 Person 객체가 문법이 간결하고 직관적임.

```tsx
class Person {
first: string;
last: string;

constructor(first: string, last: string) {
this.first = first;
this.last = last;
}

getName() {
return this.first + " " + this.last;
}
}

const marie = new Person("Marie", "Curie");
const personName = marie.getName();
```

### var 대신 let/const 사용하기

### for(;;) 대신 for-of 또는 배열 메서드 사용하기

- 코드가 짧고 인덱스 변수를 사용하지 않기 때문에 실수를 줄일 수 있다.
- 인덱스가 필요한 경우는 forEach 메서드 사용

```tsx
for (const el of array) {
// ...
}

array.forEach((el, i) => {
// ...
});
```

### 함수 표현식보다 화살표 함수 사용하기

- 화살표 함수를 사용하면 상위 스코프의 this를 유지할 수 있다.
- 컴파일 옵션에 noImplicitThis(또는 strict)를 설정하면 타입스크립트가 this 바인딩 관련 오류를 표시해줌

```tsx
class Foo {
method() {
console.log(this);
[1, 2].forEach((i) => {
console.log(this);
});
}
}

const f = new Foo();
f.method();
// 항상 Foo, Foo, Foo을 출력합니다.
```

### 단축 객체 표현과 구조 분해 할당 사용하기

```tsx
const x = 1,
y = 2,
z = 3;
const pt = { x, y, z };

const { props } = obj;
const { a, b } = props;
```

### 함수 매개변수 기본값 사용하기

```tsx
function parseNum(str, base = 10) {
return parseInt(str, base);
}
```

### 저수준 프로미스나 콜백 대신 async/await 사용하기

- 코드가 간결해져 버그나 실수를 방지한다
- 비동기 코드에 타입 정보가 전달되어 타입 추론을 가능하게 한다.

```tsx
async function getJSON(url: string) {
const response = await fetch(url);
return response.json();
}
```

### 연관 배열에 객체 대신 Map과 Set 사용하기

```tsx
function countWords(text:string) {
cosnt counts: {[word: string]: number) = {};
for (const word of text.split(/[\s,.\+/)) {
counts[word] = 1 + (counts[word] || 0);
}
return counts;
}

console.log(countWords('Objects have a constructor'));

{
Objects: 1,
have: 1,
a: 1,
constructor: "1function Object() { [native code] }" // 예상하지 못한 동작
}

// Map 사용하기
function countWordsMap(text: string) {
const counts = new Map<string, number>();
for (const word of text.split(/[\s,.\+/)) {
count.set(wrod, 1 + (counts.get(word) }} 0));
}
return counts;
}
```

### 타입스크립트에 use strict 넣지 않기

- 타입스크립트에서 수행되는 안전성 검사가 엄격 모드보다 훨씬 더 엄격한 체크를 하기 때문에, 타입스크립트 코드에서 ‘user strict’는 무의미하다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## [ITEM 59] 타입스크립트 도입 전에 @ts-check 와 JSDoc으로 시험해보기

- ts-check 지시자는 noImplicitAny 설정을 해제한 것보다 헐거운 체크를 수행한다.

### 선언되지 않은 전역 변수

- 변수를 제대로 인식할 수 있도록 별도로 타입 선언 파일을 만든다

### 알 수 없는 라이브러리

- 서드파티 라이브러리를 사용하는 경우, 서드파티 라이브러리의 타입 정보를 알아야 ㅎ란다.
- 서드파티 라이브러리의 타입 선언을 설치한다.

### DOM 문제

- 타입 단언문을 사용한다
- 타입 단언문을 사용하지 못하는 경우 JSDoc을 사용하여 타입 단언을 대체할 수 있다.

### 부정확한 JSDoc

- ts-check 지시자와 JSDoc 주석을 장기간 사용하는 것은 좋지 않다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## [ITEM 60] allowJs로 타이스크립트와 자바스크립트 같이 사용하기

- allowJs 컴파일러 옵션을 통해, 마이그레이션 중에 자바스크립트와 타입스크립트 파일을 서로 임포트할 수 있게 한다.
- 대규모 마이그레이션 작업 전에 테스트와 빌드 체인에 타입스크립트를 적용해야 한다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## [ITEM 61] 의존성 관계에 따라 모듈 단위로 전환하기

- 다른 모듈에 의존하지 않는 최하단 모듈부터 작업을 시작해서 의존성의 최상단에 있는 모듈을 마지막으로 완성해야 한다.
- 서드파티 라이브러리 타입 정보를 가장 먼저 해결해야한다.
- 마이그레이션 할 때는 타입 정보 추가만 하고, 리팩토링을 해서는 안 된다. (나중에 리팩)

### 선언되지 않은 클래스 멤버

- 자바스크립트는 클래스 멤버 변수를 선언할 필요가 없지만, 타입스크립트에서는 명시적으로 선언해야 함

### 타입이 바뀌는 값

- 한번에 생성하기 곤란한 경우에는 타입 단언문을 사용할 수도 있음

```tsx
const state = {};
state.name = 'New York'; // 오류
state.capital = 'Albany'; //오류

// 한번에 생성
const state = {
name: 'New York';
capital: 'Albany';
}; // 정상

//타입 단언문 사용
interface State {
name: string;
capital: string;
}

const state = {} as State;
state.name = 'New York';
state.capital = 'Albany';

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## [ITEM 62] 마이그레이션의 완성을 위해 noImplicitAny 설정하기

- noImplicitAny 설정이 없으면 타입 선언과 관려된 실제 오류가 드러나지 않는다.
- 처음에는 noImplicitAny를 로컬에만 설정하고 타입 오류를 점진적으로 수정한다.