Skip to content

πŸ’Ž μˆ«μžμ•Όκ΅¬ κ²Œμž„μ„ TS둜 κ΅¬ν˜„ν•œ λ’€ Effective Typescript λ‚΄μš© 적용 해보기 (Effective Typescript study 과제)

Notifications You must be signed in to change notification settings

Gamangjum-lihou/typescript-baseball-refactor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ’Ž Typescript둜 λ―Έμ…˜ μ½”λ“œ μž‘μ„±ν•˜κΈ°

πŸ“Œ μ½”λ“œ


❗️ Typescript 쑰건

  • μ™ΈλΆ€λΌμ΄λΈŒλŸ¬λ¦¬λŠ” index.d.ts νŒŒμΌμ„ λ§Œλ“€μ–΄μ„œ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.
  • λͺ¨λ“  νŒŒμΌμ€ TS둜 μž‘μ„±ν•΄μ•Ό ν•œλ‹€.
  • tsconfig.json μΆ”κ°€ μ„€μ •
    • noImplicitAny : true
    • strictNullChecks : true


πŸ“š Effective Typescript 적용 과제

πŸ“Œ λͺ©μ°¨


1️⃣ μ‹ ν˜„ν˜Έ

1. νƒ€μž… λ‹¨μ–Έλ³΄λ‹€λŠ” νƒ€μž… 선언을 μ‚¬μš©ν•˜κΈ° (μ•„μ΄ν…œ 9)

class Computer {
  #number: number[];

  constructor() {
    this.#number = this.generate();
    console.log(this.#number);
  }
  ...
}
class Player {
  #numbers: number[];

  #ballCounts: { strike: number; ball: number; };

  storeNumber(numbers: number[]) {
    this.#numbers = numbers;
  }
  ...
}
  • νƒ€μž… ν‘œμ‹œλ₯Ό μœ„ν•œ λ°©λ²•μœΌλ‘œλŠ” νƒ€μž… μ„ μ–Έκ³Ό νƒ€μž… 단언 두 가지 방법이 μ‘΄μž¬ν•˜λ‚˜, νƒ€μž… 단언이 κΌ­ ν•„μš”ν•œ κ²½μš°κ°€ μ•„λ‹ˆλΌλ©΄, μ•ˆμ „μ„± 체크도 λ˜λŠ” νƒ€μž… 선언을 μ‚¬μš©ν•˜λŠ”κ²ƒμ΄ μ’‹κΈ°λ•Œλ¬Έμ— νƒ€μž… 선언을 μ‚¬μš©ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
  • νƒ€μž… 단언은 νƒ€μž… 체컀가 νŒλ‹¨ν•˜λŠ” νƒ€μž…λ³΄λ‹€ μž‘μ„±μžμΈ λ‚΄κ°€ νŒλ‹¨ν•˜λŠ” νƒ€μž…μ΄ 더 μ •ν™•ν•  λ•Œ μ˜λ―Έκ°€ μžˆλŠ”λ°, 이 κ²½μš°μ—λŠ” ν•΄λ‹Ήλ˜μ§€ μ•ŠλŠ”λ‹€κ³  μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€.

2. ν•¨μˆ˜ ν‘œν˜„μ‹μ— νƒ€μž… μ μš©ν•˜κΈ° (μ•„μ΄ν…œ 12)

readPlayerCommand(callback: Function) {
  Console.readLine(GAME_MESSAGE.inGame, (input: string) => {
    checkCorrectNumber(input);
    callback(input);
  });
}
  • ν•΄λ‹Ή μ½”λ“œλŠ” InputView λ‚΄λΆ€μ˜ μ½”λ“œμΈλ°, νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œλŠ” ν•¨μˆ˜ λ¬Έμž₯κ³Ό ν•¨μˆ˜ ν‘œν˜„μ‹μ„ κ΅¬λΆ„ν•©λ‹ˆλ‹€.
  • νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œ ꢌμž₯λ˜λŠ” 사항은 ν•¨μˆ˜ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•˜λŠ” 것 μž…λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ ν•¨μˆ˜ λ§€κ°œλ³€μˆ˜λΆ€ν„° λ°˜ν™˜κ°’κΉŒμ§€ 전체λ₯Ό ν•¨μˆ˜ νƒ€μž…μœΌλ‘œ μ‚¬μš©ν•˜μ—¬ μž¬μ‚¬μš© ν•  수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.
  • λ”°λΌμ„œ 객체 λ‚΄λΆ€ λ©”μ†Œλ“œλ‘œ μ„ μ–Έν•œ readPlayerCommand, 그리고 이와 μœ μ‚¬ν•œ ν˜•νƒœμ˜ κΈ°λŠ₯듀을 λͺ¨λ‘ ν•¨μˆ˜ ν‘œν˜„μ‹μœΌλ‘œ λ°”κΎΈμ–΄μ£ΌλŠ”κ²Œ νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œ ꢌμž₯ν•˜λŠ” λ°©λ²•μœΌλ‘œ λ³΄μž…λ‹ˆλ‹€.

3. μΆ”λ‘  κ°€λŠ₯ν•œ νƒ€μž…μ„ μ‚¬μš©ν•΄ μž₯ν™©ν•œ μ½”λ“œ λ°©μ§€ν•˜κΈ° (μ•„μ΄ν…œ 19)

export const GAME_MESSAGE = Object.freeze({
  start: '숫자 야ꡬ κ²Œμž„μ„ μ‹œμž‘ν•©λ‹ˆλ‹€.',
  inGame: '숫자λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš” : ',
  end: '3개의 숫자λ₯Ό λͺ¨λ‘ λ§žνžˆμ…¨μŠ΅λ‹ˆλ‹€! κ²Œμž„ μ’…λ£Œ',
  option: 'κ²Œμž„μ„ μƒˆλ‘œ μ‹œμž‘ν•˜λ €λ©΄ 1, μ’…λ£Œν•˜λ €λ©΄ 2λ₯Ό μž…λ ₯ν•˜μ„Έμš”.',
});

export const ERROR_MESSAGE = Object.freeze({
  invalidNumber: '[ERR] μœ νš¨ν•˜μ§€ μ•Šμ€ μž…λ ₯μž…λ‹ˆλ‹€',
  invalidCommand: '[ERR] μœ νš¨ν•˜μ§€ μ•Šμ€ μ’…λ£Œ/μž¬μ‹œμž‘ μž…λ ₯μž…λ‹ˆλ‹€',
});
  • νƒ€μž… 슀크립트λ₯Ό λ¨Όμ € μ ‘ν•œ κ°œλ°œμžκ°€ κ°€μž₯ 많이 ν•˜λŠ”κ±΄ λͺ¨λ“  μ½”λ“œμ— νƒ€μž… ꡬ문을 λ„£λŠ” κ²ƒμ΄λ‚˜, νƒ€μž… 체컀가 있기 λ•Œλ¬Έμ— λͺ¨λ“  λ³€μˆ˜μ— νƒ€μž…μ„ μ„ μ–Έν•˜λŠ”κ±΄ λΉ„μƒμ‚°μ μž…λ‹ˆλ‹€.
  • νƒ€μž… 좔둠이 λœλ‹€λ©΄ λͺ…μ‹œμ  νƒ€μž… ꡬ문은 ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 였히렀 λ°©ν•΄κ°€ λ©λ‹ˆλ‹€.
  • νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” 더 λ³΅μž‘ν•œ 객체 λ˜ν•œ μΆ”λ‘ ν•  수 μžˆκΈ°λ•Œλ¬Έμ— νƒ€μž…μ„ μž₯ν™©ν•˜κ²Œ λͺ¨λ‘ λ‹¬μ•„μ£ΌλŠ” 것 보단 μΆ”λ‘  κ°€λŠ₯ν•œ νƒ€μž…μ„ μ‚¬μš©ν•˜λŠ”κ²Œ μ’‹μŠ΅λ‹ˆλ‹€.

4. ν•œκΊΌλ²ˆμ— 객체 μƒμ„±ν•˜κΈ° (μ•„μ΄ν…œ 23)

class Computer {
  #number: number[];

  constructor() {
    this.#number = this.generate();
    console.log(this.#number);
  }
  ...
}
  • 객체λ₯Ό 생성할 λ–„λŠ” 속성을 ν•˜λ‚˜μ”© μΆ”κ°€ν•˜κΈ°λ³΄λ‹€λŠ” μ—¬λŸ¬ 속성을 ν¬ν•¨ν•΄μ„œ ν•œκΊΌλ²ˆμ— 생성해야 νƒ€μž… 좔둠에 μœ λ¦¬ν•©λ‹ˆλ‹€.
  • μ•ˆμ „ν•œ νƒ€μž…μœΌλ‘œ 속성을 μΆ”κ°€ν•˜λ €λ©΄ 객체 μ „κ°œ ({...a, ...b})λ₯Ό μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.
  • μ‘°κ±΄λΆ€λ‘œ 속성을 μΆ”κ°€ν•˜κ³ μ‹Άλ‹€λ©΄ ? λ₯Ό μ‚¬μš©ν•©μ‹œλ‹€.

5. 곡개 API에 λ“±μž₯ν•˜λŠ” λͺ¨λ“  νƒ€μž…μ„ μ΅μŠ€ν¬νŠΈν•˜κΈ° (μ•„μ΄ν…œ 47)

declare module '@woowacourse/mission-utils' {
  class Console {
    static readLine(input: string, callback: Function): void;
    static print(message: string): void;
    static close(): void;
  }

  class Random {
    static pickNumberInRange(start: number, end: number): number;
  }
}
  • νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•˜λ‹€λ³΄λ©΄ μ„œλ“œνŒŒν‹°μ˜ λͺ¨λ“ˆμ—μ„œ μ΅μŠ€ν¬νŠΈλ˜μ§€ μ•Šμ€ νƒ€μž… 정보가 ν•„μš”ν•œ κ²½μš°κ°€ μƒκΉλ‹ˆλ‹€
  • λΆˆν•„μš”ν•œ anyλ₯Ό ν”Όν•˜κΈ° μœ„ν•΄μ„œλΌλ„ νƒ€μž…μ„ λͺ…μ‹œμ μœΌλ‘œ μž‘μ„±ν•©μ‹œλ‹€.
  • 곡개 api λ§€κ°œλ³€μˆ˜μ— λ†“μ΄λŠ” μˆœκ°„ νƒ•νŒμ€ λ…ΈμΆœλ˜λ―€λ‘œ μˆ¨κΈ°λ €ν•˜μ§€λ§κ³  라이브러리 μ‚¬μš©μžλ₯Ό μœ„ν•΄ λͺ…μ‹œμ μœΌλ‘œ νƒ€μž…μ„ μ΅μŠ€ν¬νŠΈν•˜λŠ”κ²ƒμ΄ μ’‹μŠ΅λ‹ˆλ‹€.

6. λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈλ‘œ μž‘μ„±ν•˜κΈ° (1) (μ•„μ΄ν…œ 58)

// 클래슀
class BaseBallController {
  #computer: Computer;

  #player: Player;

  constructor() {
    this.#player = new Player();
  }

  start = () => {
    OutputView.printStart();
    this.#computer = new Computer();
    this.getPlayerCommand();
  };
  
  ...
}
// import, export
import { Random } from "@woowacourse/mission-utils";
export default Computer;
  • νƒ€μž…μŠ€ν¬λ¦½νŠΈ 컴파일러λ₯Ό μžλ°”μŠ€ν¬λ¦½νŠΈ 트랜슀파일러둜 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μƒμœ„μ§‘ν•©μ΄κΈ°λ•Œλ¬Έμ—, μ΅œμ‹  λ²„μ „μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ₯Ό μ˜›λ‚  λ²„μ „μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œλ‘œ λ³€ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ”°λΌμ„œ λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ 문법을 μ‚¬μš©ν•˜λŠ”κ²ƒμ„ ꢌμž₯ν•©λ‹ˆλ‹€.
  • ECMAScript의 λͺ¨λ“ˆ, ν”„λ‘œν† νƒ€μž… λŒ€μ‹  클래슀, var λŒ€μ‹  let/const λ“±κ³Ό 같은 μš”μ†Œλ“€μ΄ μžˆμŠ΅λ‹ˆλ‹€.

7. λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈλ‘œ μž‘μ„±ν•˜κΈ° (2) (μ•„μ΄ν…œ 58)

// ν™”μ‚΄ν‘œ ν•¨μˆ˜
start = () => {
  OutputView.printStart();
  this.#computer = new Computer();
  this.getPlayerCommand();
};

getPlayerCommand = () => {
  InputView.readPlayerCommand(this.sendPlayerCommand);
};

sendPlayerCommand = (input: string) => {
  this.#player.storeNumber(input.split('').map(Number));
  this.playBall();
};
  • this ν‚€μ›Œλ“œλŠ” 일반적인 λ³€μˆ˜λ“€κ³ΌλŠ” λ‹€λ₯Έ μŠ€μ½”ν”„ κ·œμΉ™μ„ κ°€μ§€κΈ°λ•Œλ¬Έμ—, μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ κ°€μž₯ μ–΄λ €μš΄ κ°œλ… 쀑 ν•˜λ‚˜μž…λ‹ˆλ‹€.
  • ν™”μ‚΄ν‘œ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ μƒμœ„ μŠ€μ½”ν”„μ˜ thisλ₯Ό μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 일반 ν•¨μˆ˜λ³΄λ‹€ ν™”μ‚΄ν‘œ ν•¨μˆ˜κ°€ 더 직관적이며 μ½”λ“œλ„ 간결해지기 λ•Œλ¬Έμ— 가급적 ν™”μ‚΄ν‘œ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.


2️⃣ 강철원

1. νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ„€μ • μ΄ν•΄ν•˜κΈ° (Item 2)

"noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */,
"strictNullChecks": true
  • νƒ€μž…μŠ€ν¬λ¦½νŠΈ 섀정은 μ»€λ§¨λ“œ 라인을 μ΄μš©ν•˜κΈ°λ³΄λ‹€λŠ” tsconfig.json을 μ‚¬μš©ν•˜λŠ”κ²Œ μ’‹λ‹€.
  • 'undefinedλŠ” 객체가 μ•„λ‹™λ‹ˆλ‹€' 같은 λŸ°νƒ€μž„ 였λ₯˜λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ strictNullChecksλ₯Ό μ„€μ •ν•˜λŠ” 것이 μ’‹λ‹€'
  • μžλ°”μŠ€ν¬λ¦½νŠΈ ν”„λ‘œμ νŠΈλ₯Ό νƒ€μž…μŠ€ν¬λ¦½νŠΈλ‘œ μ „ν™˜ν•˜λŠ” 게 μ•„λ‹ˆλΌλ©΄ noImplicitAnyλ₯Ό μ„€μ •ν•˜λŠ” 것이 μ’‹λ‹€

2. any νƒ€μž…μ€ κ°€λŠ₯ν•œ ν•œ 쒁은 λ²”μœ„μ—μ„œλ§Œ μ‚¬μš©ν•˜κΈ° (Item 38)

λ¬Έλ§₯μƒμœΌλ‘œ xλΌλŠ” λ³€μˆ˜κ°€ λ™μ‹œμ— Foo νƒ€μž…κ³Ό Bar νƒ€μž…μ— ν• λ‹Ή κ°€λŠ₯ν•˜λ‹€λ©΄, 였λ₯˜λ₯Ό μ œκ±°ν•˜λŠ” 방법은 두 가지이닀.

function f1() {
  const x: any = expressionReturningFoo(); //  μ΄λ ‡κ²Œ x
  processBar(x);
}

function f2() {
  const x = expressionReturningFoo();
  processBar(x as any); // 이게 더 μ’‹μŒ
  // why? λ‹€λ₯Έ μ½”λ“œμ— 영ν–₯ x
}
checkNumber(input: unknown) {
    if (/\D/.test(input as any)) {
      throw new ValidationError(ERROR_MESSAGE.only_number);
    }
  },

  checkLength(input: string) {
    if (input.length !== 1) {
      throw new ValidationError(ERROR_MESSAGE.length_one);
    }
  },
  • μ˜λ„μΉ˜ μ•Šμ€ νƒ€μž… μ•ˆμ „μ„±μ˜ 손싀을 ν”Όν•˜κΈ° μœ„ν•΄ any의 μ‚¬μš© λ²”μœ„λ₯Ό μ΅œμ†Œν•œμœΌλ‘œ μ’ν˜€μ•Ό ν•œλ‹€.
  • ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μ΄ any인 경우 νƒ€μž… 아전성이 λ‚˜λΉ μ§„λ‹€. λ”°λΌμ„œ any νƒ€μž…μ„ λ°˜ν™˜ν•˜λ©΄ μ ˆλŒ€ μ•ˆλœλ‹€.
  • κ°•μ œλ‘œ νƒ€μž… 였λ₯˜λ₯Ό μ œκ±°ν•˜λŠ” 방법은 any 말고 @ts-ignore 도 κ°€λŠ₯ν•˜λ‹€.


3. λͺ¨λ₯΄λŠ” νƒ€μž…μ˜ κ°’μ—λŠ” any λŒ€μ‹  unknown을 μ‚¬μš©ν•˜κΈ° (Item 42)

  • unknown은 any λŒ€μ‹  μ‚¬μš©ν•  수 μžˆλŠ” μ•ˆμ „ν•œ νƒ€μž…μ΄λ‹€. μ–΄λ– ν•œ 값이 μžˆμ§€λ§Œ κ·Έ νƒ€μž…μ„ μ•Œμ§€ λͺ»ν•˜λŠ” 경우라면 unknown을 μ‚¬μš©ν•˜λ©΄ λœλ‹€.
  • unknown을 μ‚¬μš©ν•˜λ €λ©΄ νƒ€μž… 단언문 or νƒ€μž…μ²΄ν¬λ₯Ό ν•΄μ•Όν•œλ‹€.
class GameNumber {
  #inputNumbers;

  constructor(input: unknown) {
    this.#inputNumbers = input;
    this.#checkInput();
  }

  #checkInput() {
    this.#checkNumber();
    this.#checkZero();
    this.#checkNumberOfDigits();
    this.#checkDuplication();
  }

  #checkNumber() {
    if (this.#isNotNumber()) throw new ValidationError(ERROR_MESSAGE.only_number);
    this.#inputNumbers = Number(this.#inputNumbers);
  }

  #isNotNumber() {
    return isNaN(Number(this.#inputNumbers));
  }

  #checkZero() {
    if (this.#haveZero()) throw new ValidationError(ERROR_MESSAGE.not_zero);
  }

  #haveZero() {
    if (typeof this.#inputNumbers === 'number') {
      return [...this.#inputNumbers.toString()].includes('0');
    }
  }
const GameCommand = {
  checkGameCommand(input: unknown) {
    this.checkNumber(input);
    this.checkLength(input as string);
    this.checkOneOrTwo(input as string);
  },

  checkNumber(input: unknown) {
    if (/\D/.test(input as any)) {
      throw new ValidationError(ERROR_MESSAGE.only_number);
    }
  },

  checkLength(input: string) {
    if (input.length !== 1) {
      throw new ValidationError(ERROR_MESSAGE.length_one);
    }
  },

  checkOneOrTwo(input: string) {
    if (!/1|2/.test(input)) {
      throw new ValidationError(ERROR_MESSAGE.one_or_two);
    }
  },
};

export default GameCommand;
  • μΆ”κ°€ 1 가끔 unknwon λŒ€μ‹  μ œλ„ˆλ¦­ λ§€κ°œλ³€μˆ˜κ°€ μ‚¬μš©λ˜λŠ” κ²½μš°λ„ μžˆλ‹€.
function safeParseYAML(yaml: string): unknown {
  return parseYAML(yaml);
}

function safeParseYAML<T>(yaml: string): T {
  return parseYAML(yaml);
}

μ œλ„ˆλ¦­μ„ μ‚¬μš©ν•œ μŠ€νƒ€μΌμ€ νƒ€μž… 단언문과 달라 λ³΄μ΄μ§€λ§Œ κΈ°λŠ₯μ μœΌλ‘œλŠ” λ™μΌν•˜λ‹€. μ œλ„ˆλ¦­λ³΄λ‹€λŠ” unknown을 λ°˜ν™˜ν•˜κ³  μ‚¬μš©μžκ°€ 직접 단언문을 μ‚¬μš©ν•˜κ±°λ‚˜ μ›ν•˜λŠ” λŒ€λ‘œ νƒ€μž…μ„ μ’νžˆλ„λ‘ κ°•μ œν•˜λŠ” 것이 μ’‹λ‹€.

  • μΆ”κ°€ 2

{} νƒ€μž…λ„ μ‘΄μž¬ν•˜λŠ”λ° μ΄λŠ” unknown λ³΄λ‹€λŠ” λ²”μœ„κ°€ μ•½κ°„ 쒁닀.

{} νƒ€μž…μ€ nullκ³Ό undefinedλ₯Ό μ œμ™Έν•œ λͺ¨λ“  값을 ν¬ν•¨ν•œλ‹€. {} νƒ€μž…μ€ unknown νƒ€μž…μ΄ λ„μž…λ˜κΈ° μ „μ—λŠ” {}κ°€ 더 일반적으둜 μ‚¬μš©λ˜μ—ˆλ‹€. μ΅œκ·Όμ‚¬μš©μ€ λ“œλ¬Όλ‹€.

let emptyObject: {} = 123; // 숫자
emptyObject = 'hello'; // λ¬Έμžμ—΄
emptyObject = [1, 2, 3]; // λ°°μ—΄
let emptyObject: {} = null; // 였λ₯˜ λ°œμƒ
let emptyObject: {} = undefined; // 였λ₯˜ λ°œμƒ


4. νƒ€μž… μ—°μ‚°κ³Ό μ œλ„ˆλ¦­ μ‚¬μš©μœΌλ‘œ 반볡 쀄이기 (Item 14)

κ°’μ˜ ν˜•νƒœμ— ν•΄λ‹Ήν•˜λŠ” νƒ€μž…μ„ μ •μ˜ν•˜κ³  싢을 λ•Œ λ”°λ‘œ interface λ§Œλ“€ ν•„μš”μ—†μ΄ typeofλ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.

class BaseballController {
  #view: typeof View;

  #model: Model;

  #validator: Validator;
const View = {
  printStart() {
    OutputView.printStart();
  },

  readGameNumbers(callback: callback) {
    InputView.readLine(`${INPUT_MESSAGE.game_number}`, callback);
  },

  readGameCommand(callback: callback) {
    InputView.readLine(`${INPUT_MESSAGE.game_command}`, callback);
  },

  printHint(value: IprintHint) {
    OutputView.printHint(value);
  },

  printSuccess() {
    OutputView.printSuccess();
  },

  printError(error: IError) {
    OutputView.printError(error);
    OutputView.printGameEnd();
  },

  finishGame() {
    OutputView.finishGame();
  },
};

export default View;
image

5.νƒ€μž… 쒁히기 (Item 22)

νƒ€μž… μ’νžˆκΈ°λŠ” νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ 넓은 νƒ€μž…μœΌλ‘œλΆ€ν„° 쒁은 νƒ€μž…μœΌλ‘œ μ§„ν–‰ν•˜λŠ” 과정을 λ§ν•œλ‹€.

before

type Ivalidator = typeof Validator & {
  [key:string] : (input:unknown) => void;
}


#validator: Ivalidator;



#hasErrorWhanCheckInput(numbers: string, inputName: string) {
    try {
      this.#validator[inputName](numbers);
    } catch (error) {
      return this.#handleError(error as ErrorWithCause);
    }
  }
  

after

  #validator: typeof Validator;

  type inputName = 'checkGameNumbers' | 'checkGameCommand';
  
   #hasErrorWhanCheckInput(numbers: string, inputName: inputName) {
    try {
      this.#validator[inputName](numbers);
    } catch (error) {
      return this.#handleError(error as ErrorWithCause);
    }
  }

About

πŸ’Ž μˆ«μžμ•Όκ΅¬ κ²Œμž„μ„ TS둜 κ΅¬ν˜„ν•œ λ’€ Effective Typescript λ‚΄μš© 적용 해보기 (Effective Typescript study 과제)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published