태그
요약프론트엔드독서
최종 편집
Dec 30, 2022 2:33 AM
발행일
November 30, 2021
Dan Vanderkam의 책 Effective TypeScript: 62 Specific Ways to Improve Your TypeScript 내용 중 메모할 부분만 기록한다. 책 내용이 무척 좋다.
완독 후 간단 리뷰
- 완독해야만 제대로 학습한 것이라는 집착은 이제 별로 없지만 그래도 처음부터 끝까지 읽었을 때의 묘한 기쁨이 있다.
- 내가 지금까지 읽은 타입스크립트 글을 통틀어 가장 괜찮은 녀석이었다. 자바스크립트로 된 프로젝트를 타입스크립트로 바꾸고 싶은 팀이라면 크게 도움이 될 좋은 책이다. 타입스크립트뿐 아니라 자바스크립트의 원리도 이해하기 쉽게 설명해주어서, 사실 웹개발자라면 누구라도 읽어도 좋을 거라고 본다.
- FE재남님이 유튜브에 올리시는 <자바스크립트 딥 다이브> 스터디에서 알게 된 내용도 책에 종종 나와서, 묘하게 복습하는 기분의 시너지가 있었다.
- 다음 책은 원래 Software Engineering at Google로 계획했다가, 최근 본 Talks at Google 강연이 무척 끌려서 A Philosophy of Software Design 으로 정했다. 마침 2021년에 개정판도 나왔더라.
Item 9: Prefer Type Declarations to Type Assertions
- 함수 타이핑할 때
(name: Person)
과(name): Person
의 차이. 후자는 리턴값까지 타이핑해준다. - type assertion은 웬만하면 피하고, 타입스크립트보다 개발자가 더 많이 알고 있을 때 쓰면 좋다. 예를 들어 타입스크립트는 DOM 정보는 모름
Item 10: Avoid Object Wrapper Types (String, Number, Boolean, Symbol, BigInt)
- object wrapper의 개념은 몰랐다. primitive는 스스로 가지는 메서드가 없음.
- 메서드는 프로토타입이 가지는 건데 프리미티브는 프로토타입이 없기 때문.
- 따라서 메서드 호출은 사실 인스턴스로 감싸서 해준 다음 폐기하는 것이다.
String(“abc”).charAt(0)
charAt
은 String.prototype 에 정의되어 있음
Item 11: Recognize the Limits of Excess Property Checking
const x: T = …
와const x; const y: T = x
의 컴파일 결과가 다름- excess prop check는 obj literal에 대해서만 함. 이건 실제로 런타임 에러를 발생시키는 건 아니나 개발자가 실수했을 수 있는 부분을 발견해주는 것이다.
Item 13: Know the Differences Between type and interface
- 시간이 지나면서 둘 사이의 차이가 거의 없어짐
- 인터페이스는 union 같은 complex type을 extend 못함
- 일반적으로는 타입 쓰는 게 나음
- 인터페이스는 augment 가능. declaration merge 가능하다는 것 때문에 외부 공개용 패키지나 타입에서는 인터페이스로 많이 씀.
Item 16: Prefer Arrays, Tuples, and ArrayLike to number Index Signatures
- object key는 언제나 string으로 바뀐다. num으로 넣어도 알아서 바뀜.
- array도 js에서는 오브젝트이므로 array index도 사실은 스트링이다.
object.keys
로 어레이 넣어보면 스트링 나옴. - 하지만 ts에서는 number 타입으로 index를 유지함. 이건 유용한 fiction이지만, fiction임을 기억하고 있어야 함
Item 17: Use readonly to Avoid Errors Associated with Mutation
- readonly 붙으면 타입 자체가 달라짐! 몰랐다.
- You can read from its elements, but you can’t write to them.
- You can read its length, but you can’t set it (which would mutate the array).
- You can’t call pop or other methods that mutate the array.
- TypeScript checks that the parameter isn’t mutated in the function body.
- Callers are assured that your function doesn’t mutate the parameter.
- Callers may pass your function a readonly array.
Item 19: Avoid Cluttering Your Code with Inferable Types
- no-inferrable-type eslint 사용 가능
Item 21: Understand Type Widening
- Type Widening: 변수에 값을 넣어 초기화할때 그 값 자체보다 얼마나 더 넓은 타입을 지정하는가.
const
를 쓰면 프리미티브의 타입은 효과적으로 좁아지지만 그래도 오브젝트라면 타입 시스템이 추론하기 어려움- ts의 기본 동작을 오버라이드하는 방법
- explicit type annotation
- as const - narrowest possible
- context 추가하기 (함수 파라미터로 사용한다거나) → 이후 아이템에서 설명
Item 24: Be Consistent in Your Use of Aliases
- type aliasing은 컨트롤 플로우 분석을 깰 수 있다. destructure하면 되지만, 그러면 값이 달라져버릴 수 있는 위험도 있다는 것은 명심.
type X = { y?: number }
const x: X;
if (x.y) {} // x.y가 존재함이 보장됨
const y = x.y;
if (y) {} // x.y가 존재함이 보장되지 않음
const { y } = x;
if (y) {} // y가 존재함이 보장되나, x[y] = ... 로 새로 할당이 가능하므로 원본과 달라질 수 있음
Item 25: Use async Functions Instead of Callbacks for Asynchronous Code
- Promise.race 로 타임아웃 구현이 가능. 처음 알았다.
Item 29: Be Liberal in What You Accept and Strict in What You Produce
- 제목 자체가 좋음
- Array, ArrayLike처럼 인풋은 더 넓게 받아주면 사용부애서 편함. 브레이킹 체인지도 적어질듯
- 근데 이게 항상 좋은지는 모르겠다. 사용하는 방식이 일관적이지 않게 될듯
Item 30: Don’t Repeat Type Information in Documentation
- mutate가 일어나면 안 되는 파라미터면 readonly 붙여라
- 타입만으로 알기 어려운 정보는 이름에 추가하라. unit이라든가
Item 34: Prefer Incomplete Types to Inaccurate Types
- 타입을 너무 좁히려다가 부정확하게 될바에는 넓게 해라
Item 37: Consider “Brands” for Nominal Typing
- _brand 를 덧붙이고 type guard를 만듦으로써 실제로 오브젝트 키를 추가하지 않고 타입 시스템만으로 안전하게 할 수 있음
Item 44: Track Your Type Coverage to Prevent Regressions in Type Safety
- noImplcitAny 써도 explicit any와 써드파티에서의 any는 못 막음
- npx type-coverage로 any가 아닌 타입 정의 비율 볼 수 있음
Item 46: Understand the Three Versions Involved in Type Declarations
- @types 패키지 설치하면 세가지 문제 있을 수 있음
- 라이브러리가 타입보다 더 최신이거나, 타입이 라이브러리보다 최신
- 패치 버전만 바뀌면 이론상 문제 없어야 하지만 아닐 수도 있음. 버전 싱크 필요
- 타입이 새 타입스크립트 버전을 필요로 할 때
- ts 버전을 고정시킬 수 있음 ‘npm install --save-dev @types/lodash@ts3.1’
- 타입 패키지 a가 b에 의존하는데 b도 직접 깔았다거나 해서 둘이 호환 안되는 버전일때
- npm ls 로 트랙 다운 가능
- transitive라서 문제. 직접 싱크 맞춰야 함
Item 48: Use TSDoc for API Comments
- 함수에(public api) 주석 달 때는 그냥 인라인 코멘트보다는 jsdoc이나 tsdoc 스타일로 달면 vscode에서 잘 보인다
- param, returns, markdown 사용 가능
/**
* Generate a **greeting**.
* @param name Name of the person to greet
* @param salutation The person's title
* @returns A greeting formatted for human consumption.
*/
Item 51: Mirror Types to Sever Dependencies
- Use structural typing to sever dependencies that are nonessential.
- Don’t force JavaScript users to depend on @types. Don’t force web developers to depend on NodeJS.
Item 52: Be Aware of the Pitfalls of Testing Types
- dtslint 사용 가능
Item 53: Prefer ECMAScript Features to TypeScript Features
- 기본적으로 타입스크립트는 타입 시스템일 뿐이고 자바스크립트로 컴파일된 결과에 영향을 안 미쳐야 하지만, 몇 가지 예외가 있다. ECMAScript에서 스펙이 정의되기 전에 타입스크립트가 이들을 지원하려고 추가했던 기능들의 잔재다.
- 이것들을 쓸 때 조심하고, 되도록이면 네이티브 기능을 쓰자.
- enum
- 클래스에서 파라미터 프로퍼티
- 네임스페이스, ///
- 데코레이터
Item 56: Don’t Rely on Private to Hide Information
- private 키워드는 타입 시스템에 불과함
- 정보를 진정으로 숨기려면 클로저 쓸 것
- 또는 새로 나온 문법인 #으로 정의하는 걸 쓸 수도 있음
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'); // Returns false
checker.checkPassword('s3cret'); // Returns true