2024-06-15.md

๐Ÿก

DIL: ์ดํŽ™ํ‹ฐ๋ธŒ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ

์Šคํ„ฐ๋””: ์›”๊ฐ„ CS, https://github.com/monthly-cs/2024-05-effective-typescript
์ž‘์„ฑ์ผ: 2024-06-15
์ž‘์„ฑ์ž: dusunax


์•„์ดํ…œ 49: ์ฝœ๋ฐฑ์— this์— ๋Œ€ํ•œ ํƒ€์ž… ์ œ๊ณตํ•˜๊ธฐ Provide a Type for this in Callbacks if It's Part of Their API

  • JS์˜ this๋Š” ๋‹ค์ด๋‚˜๋ฏน ์Šค์ฝ”ํ”„๋‹ค. ๋™์  ์Šค์ฝ”ํ”„

    • let, const๋Š” lexical scope ๋ณ€์ˆ˜์˜ ์œ ํšจ ๋ฒ”์œ„๊ฐ€ ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ์ ์˜ ์œ„์น˜์— ์˜ํ•ด ๊ฒฐ์ •๋˜๋Š” ๋ฐฉ์‹ (์„ ์–ธ๋œ ์œ„์น˜์— ๋”ฐ๋ผ๋ผ ์Šค์ฝ”ํ”„ ๊ฒฐ์ •)

    • this๋Š” ์–ด๋””์—์„œ ํ˜ธ์ถœ๋˜์—ˆ๋ƒ์— ๋”ฐ๋ผ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค.

      • ์ธ์Šคํ„ด์Šค ์ฐธ์กฐํ•˜๋Š” ํด๋ž˜์Šค์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ž„

        class C {
          vals = [1, 2, 3];
          logSquares() {
            for (const val of this.vals) {
              console.log(val ** 2);
            }
          }
        }
        
        const c = new C();
        c.logSquares();
        
        const c = new C();
        const method = c.logSquares; // ๋ฉ”์†Œ๋“œ๋ฅผ ์™ธ๋ถ€ ๋ณ€์ˆ˜์— ๋„ฃ๊ธฐ
        method();
        
        // c.logSquares()
        // ์ธ์Šคํ„ด์Šค์˜ prototype์˜ logSquares ๋ฉ”์†Œ๋“œ ์‹คํ–‰
        // this์˜ ๊ฐ’์„ c๋กœ ๋ฐ”์ธ๋”ฉ, this ์ฐธ์กฐ: ์ธ์Šคํ„ด์Šค์˜ this๋Š” ์ƒ์„ฑ๋œ ๊ฐ์ฒด์˜ this
        // c.logSquares๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉ << ํ•จ์ˆ˜์˜ this๋Š” ์ „์—ญ this (strictmode์—์„œ undefined)
        
        method.call(c); // call๋กœ this ๋ฐ”์ธ๋”ฉ
        
  • prototype

    class ResetButton {
      constructor() {
        // this.onClick ๋ฉ”์„œ๋“œ์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ํ˜„์žฌ ์ธ์Šคํ„ด์Šค๋กœ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค.
        this.onClick = this.onClick.bind(this);
      }
      render() {
        // makeButton ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฒ„ํŠผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
        // ๋ฒ„ํŠผ์˜ ํ…์ŠคํŠธ๋Š” 'Reset'์ด๊ณ , ํด๋ฆญ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” this.onClick์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
        return makeButton({ text: "Reset", onClick: this.onClick });
      }
      onClick() {
        // ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
        // alert ์ฐฝ์— 'Reset'๊ณผ ํ˜„์žฌ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค
        alert(`Reset ${this}`);
      }
    }
    
  • lookup sequence

    • ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ ์˜ฌ๋ผ๊ฐ€๊ธฐ ์ „์— ๋ฐ”์ธ๋”ฉ๋œ ํ•จ์ˆ˜ ์ฐธ์กฐ

this ๋ฐ”์ธ๋”ฉ๊ณผ ๊ด€๋ จ๋œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด

  • ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋Š” ์ƒ์œ„ ์Šค์ฝ”ํ”„์˜ this๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— this ๋ฐ”์ธ๋”ฉ ๋ฌธ์ œ๋ฅผ ํšŒํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” JS์˜ this ๋ฐ”์ธ๋”ฉ์„ ๊ทธ๋Œ€๋กœ ๋ชจ๋ธ๋งํ•œ๋‹ค => this๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ณ ๋ คํ•ด์•ผํ•จ
  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ์ž์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์—์„œ this๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋กœ ์ž‘์„ฑํ•˜๋ฉด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์—๋Ÿฌ๋ฅผ ์žก์•„๋ƒ„
class ResetButton {
  render() {
    return makeButton({text: 'Reset', onClick: this.onClick});
  },
  onClick=()=>{
    alert(`Reset ${this}`)
  }
}

Things to Remember

  • Understand how this binding works.
    • this ๋ฐ”์ธ๋”ฉ ~
  • Provide a type for this in callbacks if it's part of your API.
    • API ๋งŒ๋“ค ๋•Œ ์ฝœ๋ฐฑํ•จ์ˆ˜์˜ this ํƒ€์ž… ์ œ๊ณตํ•˜๊ธฐ
  • Avoid dynamic this binding in new APIs.
    • ๋™์  ๋ฐ”์ธ๋”ฉ ํ”ผํ•˜๊ธฐ: ํ™”์‚ดํ‘œ ํ•จ์ˆ˜, ๋ช…์‹œ์  ๋ฐ”์ธ๋”ฉ bind(), ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋‚˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ this๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š๋„๋ก ์„ค๊ณ„

์•„์ดํ…œ 50: ์˜ค๋ฒ„๋กœ๋”ฉ ํƒ€์ž…๋ณด๋‹ค๋Š” ์กฐ๊ฑด๋ถ€ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ธฐ Prefer Conditional Types to Overload Signatures

ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ

  • ๋ชจํ˜ธํ•˜๊ฑฐ๋‚˜(์œ ๋‹ˆ์˜จ) ๊ณผํ•˜๊ฒŒ ๊ตฌ์ฒด์ (์ œ๋„ˆ๋ฆญ)
// โŒ ๋„ˆ๋ฌด ๋ชจํ˜ธํ•จ
declare function double(x: string | number): string | number;
const num = double(12);
//    ^? const num: string | number
const str = double("x");
//    ^? const str: string | number

// โŒ ์•„๋‹˜
declare function double<T extends string | number>(x: T): T;
const num = double(12);
//    ^? const num: 12
const str = double("x");
//    ^? const str: "x"
  • ๋˜๋Š” ์˜ค๋ฅ˜
declare function double(x: number): number;
declare function double(x: string): string;

function f(x: string | number) {
  return double(x);
  //            ~ Argument of type 'string | number' is not assignable
  //              to parameter of type 'string'

  // โŒ ์˜ค๋ฒ„๋กœ๋”ฉ ํƒ€์ž… ์ค‘์—์„œ ์ผ์น˜ํ•˜๋Š” ํƒ€์ž…์„ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ์ˆœ์ฐจ์ ์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— string | number์€ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์˜ค๋ฅ˜

  // string | number์„ number์— ํ• ๋‹นํ•  ์ˆ˜ ์—†๋‹ค.
  // string | number์„ string์— ํ• ๋‹นํ•  ์ˆ˜ ์—†๋‹ค.
  // ํ• ๋‹นํ•  ์ˆ˜ ์—†๋‹ค
}

์กฐ๊ฑด๋ถ€ ํƒ€์ž… ์‚ฌ์šฉํ•˜๊ธฐ

  • ์ œ๋„ˆ๋ฆญ์„ ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค!
    • ์œ ๋‹ˆ์˜จ์— ์กฐ๊ฑด๋ถ€ ํƒ€์ž…์„ ์ ์šฉํ•˜๋ฉด? ์กฐ๊ฑด๋ถ€ ํƒ€์ž…์˜ ์œ ๋‹ˆ์˜จ์œผ๋กœ ๋ถ„๋ฆฌ๋œ๋‹ค.
function double<T extends string | number>( // T๋Š” string | number
  x: T // x๋Š” T
): T extends string ? string : number; // ๊ทธ๋Ÿฐ๋ฐ? T๊ฐ€ string์ด๋ฉด string ๋ฆฌํ„ด, ์•„๋‹ˆ๋ฉด number

function double(x: string | number) {
  // return x + x;
  //        ~~~~~ Operator '+' cannot be applied to types 'string | number' and 'string | number'.ts(2365)
  //              (parameter) x: string | number

  return typeof x === "string" ? x + x : x + x;
}

Things to Remember

  • Prefer conditional types to overloaded type signatures. By distributing over unions, conditional types allow your declarations to support union types without additional overloads.
    • ์˜ค๋ฒ„๋กœ๋”ฉ ํƒ€์ž…๋ณด๋‹ค ์กฐ๊ฑด๋ถ€ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ถ”๊ฐ€์ ์ธ ์˜ค๋ฒ„๋กœ๋”ฉ ์—†์ด ์œ ๋‹ˆ์˜จ ํƒ€์ž… ์ง€์›
  • If the union case is implausible, consider whether your function would be clearer as two or more functions with different names.
    • ์œ ๋‹ˆ์–ธ ์ผ€์ด์Šค๊ฐ€ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ๋‹ค๋ฉด, ํ•จ์ˆ˜์˜ ๋ช…ํ™•์„ฑ์„ ์œ„ํ•ด ๋‘ ๊ฐœ ์ด์ƒ์˜ ๋‹ค๋ฅธ ์ด๋ฆ„์„ ๊ฐ€์ง„ ํ•จ์ˆ˜๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ ๊ณ ๋ คํ•˜๊ธฐ
  • Consider using the single overload strategy for implementing functions declared with conditional types.
    • ๋‹จ์ผ ํ•จ์ˆ˜ ๊ตฌํ˜„ํ•˜๊ธฐ + ์กฐ๊ฑด๋ถ€ ํƒ€์ž…

์•„์ดํ…œ 51: ์˜์กด์„ฑ ๋ถ„๋ฆฌ๋ฅผ ์œ„ํ•ด ๋ฏธ๋Ÿฌ ํƒ€์ž… ์‚ฌ์šฉํ•˜๊ธฐ Mirror Types to Sever Dependencies

  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด ํƒ€์ž… ์˜ˆ์‹œ: NodeJS ํ™˜๊ฒฝ์—์„œ ์ž…๋ ฅ๋ฐ›์„ Buffer ํƒ€์ž…์„ ์œ„ํ•ด @type/node๋ฅผ devDependency๋กœ ํฌํ•จํ•œ ๊ฒฝ์šฐ
    • Buffer ํƒ€์ž…์€ NodeJS ๊ฐœ๋ฐœ์ž๋งŒ ํ•„์š”ํ•œ ํƒ€์ž…
    • NodeJS์™€ ๋ฌด๊ด€ํ•œ ์›น ๊ฐœ๋ฐœ์ž: NodeJS ํ•„์š”์—†์Œ
    • JS ๊ฐœ๋ฐœ์ž: @types ํ•„์š”์—†์Œ
  • ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ชจ๋“ˆ => ๋ฏธ๋Ÿฌ๋งํ•œ ํƒ€์ž… ์ธํ„ฐํŽ˜์ด์Šค ๋งŒ๋“ค๊ธฐ
    • ํ•„์š”ํ•œ ์„ ์–ธ๋ถ€๋งŒ ์ถ”์ถœํ•˜์—ฌ ๋ช…์‹œํ•œ๋‹ค!
  • ๋‹ค๋งŒ, ํ”„๋กœ์ ํŠธ ์˜์กด์„ฑ์ด ๋‹ค์–‘ํ•˜๊ณ  ํ•„์ˆ˜ ์˜์กด์„ฑ์ด ๋งŽ์€ ๊ฒฝ์šฐ. ํƒ€์ž… ์„ ์–ธ์„ ๋Œ€๋ถ€๋ถ„ ์ถ”์ถœํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋ช…์‹œ์ ์œผ๋กœ @types ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์Œ
    • ์œ ๋‹›ํ…Œ์ŠคํŠธ ๋ชจํ‚นํ•  ๋•Œ๋„ ์‚ฌ์šฉ

Things to Remember

  • Avoid transitive type dependencies in published npm modules.
    • ๊ณต๊ฐœํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ „์ด์  ํƒ€์ž… ์˜์กด์„ฑ ํ”ผํ•˜๊ธฐ
      • ๋ชจ๋“ˆ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ชจ๋“ˆ์— ๋Œ€ํ•œ ํƒ€์ž… ์ •์˜ ์„ค์น˜ํ•ด์•ผํ•จ
      • ๊ด€๋ฆฌ & ์ถ”์ ํ•ด์•ผ ํ•  ํŒจํ‚ค์ง€ ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚˜๊ณ , ๋ฒ„์ „ ์ถฉ๋Œ ๋ฌธ์ œ / ๋ฐฐํฌ ๋ฐ ์—…๋ฐ์ดํŠธ ๋ณต์žกํ•ด์ง
  • 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 Node.js.
    • ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•  ๋•Œ, JS ๊ฐœ๋ฐœ์ž, Node.js ์•ˆ์“ฐ๋Š” ๊ฐœ๋ฐœ์ž์˜ ๊ฒฝ์šฐ ๊ณ ๋ คํ•˜๊ธฐ

์•„์ดํ…œ 52: ํ…Œ์ŠคํŒ… ํƒ€์ž…์˜ ํ•จ์ •์— ์ฃผ์˜ํ•˜๊ธฐ Write Tests for Your Types

  • ํ”„๋กœ์ ํŠธ๋ฅผ ๊ณต๊ฐœํ•  ๋•Œ ํ•  ๊ฒƒ: ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ, ํƒ€์ž… ์„ ์–ธ ํ…Œ์ŠคํŠธ
    • ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹ => ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์ฒดํฌํ•˜๋Š” ๋ฐฉ์‹
    • dtslint ๋˜๋Š” ํƒ€์ž… ์‹œ์Šคํ…œ ์™ธ๋ถ€์— ํƒ€์ž…์„ ๊ฒ€์‚ฌํ•˜๋Š” ๋„๊ตฌ๋„ ์‚ฌ์šฉํ•˜๊ธฐ

DefinitelyTyped ๋ฌธ์„œ ์ž˜ ๋˜์žˆ์Œ https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/README.ko.md

ํ—ฌํผ ํ•จ์ˆ˜

  • ๋ถˆํ•„์š”ํ•œ ์ถ”๊ฐ€ ๋ณ€์ˆ˜๋ฅผ ๋งŽ์ด ๋งŒ๋“ค๊ฑฐ๋‚˜, ๋ฆฐํŒ… ๊ทœ์น™์„ ๋น„ํ™œ์„ฑํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
function assertType<T>(x: T) {}
assertType<number[]>(map(["john", "paul"], (name) => name.length)); // ์ด๋ฆ„์˜ ๊ธธ์ด๋ฅผ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์˜ ๋ฆฌํ„ด ํƒ€์ž…์„ ๊ฒ€์ฆ

assertType ํ—ฌํผ ํ•จ์ˆ˜์˜ ๋ฌธ์ œ์ 

  • ํ• ๋‹น ๊ฐ€๋Šฅ์„ฑ์„ ์ฒดํฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ฌ๋ฒŒ๋„ string ๋˜๋Š” number์— ํ• ๋‹น ๊ฐ€๋Šฅ
const n = 12;
assertType<number>(n); // OK
  • ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐฏ์ˆ˜ ์˜ค๋ฅ˜ (๋” ์ ์€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง„ ํ•จ์ˆ˜๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Œ)
function assertType<T>(x: T) {}
const add = (a: number, b: number) => a + b;
assertType<(a: number, b: number) => number>(add); // OK

const double = (x: number) => 2 * x;
assertType<(a: number, b: number, c: number) => number>(double); // OK!?

๊ฐœ์„ 

  • ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…๊ณผ ๋ฐ˜ํ™˜ํƒ€์ž…์„ ๋ถ„๋ฆฌํ•˜์—ฌ ํ…Œ์ŠคํŠธ: Parameters, ReturnType
const double = (x: number) => 2 * x;
declare let p: Parameters<typeof double>;
assertType<[number, number]>(p); // ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž… ํ…Œ์ŠคํŠธ
//                           ~ Argument of type '[number]' is not
//                             assignable to parameter of type [number, number]
declare let r: ReturnType<typeof double>;
assertType<number>(r); // OK

this ํ…Œ์ŠคํŠธ ํ†ต๊ณผํ•˜๋Š” ์˜ˆ์‹œ

const beatles = ["john", "paul", "george", "ringo"]; // string[]

assertType<number[]>(
  map(beatles, function (name, i, array) {
    // ~~~ Argument of type '(name: any, i: any, array: any) => any' is
    //     not assignable to parameter of type '(u: string) => any'
    // ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ด ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ํƒ€์ž…์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š๋‹ค๊ณ  ๊ฒฝ๊ณ ํ•ฉ๋‹ˆ๋‹ค.

    assertType<string>(name); // name์€ string
    assertType<number>(i); // index๋Š” ์ˆซ์ž
    assertType<string[]>(array); // array๋Š” ๋ฌธ์ž์—ด ๋ฐฐ์—ด
    assertType<string[]>(this); // this๋Š” ์•”์‹œ์  any <- ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ
    //                   ~~~~ 'this' implicitly has type 'any'
    return name.length; //๊ฐ ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  })
);

declare function map<U, V>(
  array: U[],
  fn: (this: U[], u: U, i: number, array: U[]) => V
): V[];
// this๊ฐ€ U์˜ ๋ฐฐ์—ด์ž„์„ ๋ช…์‹œํ•จ

dtslint

  • ๋ชจ๋“ˆ์„ ์„ ์–ธ(declare)ํ•˜๋ฉด ์ „์ฒด ๋ชจ๋“ˆ์— any ํƒ€์ž…์„ ํ• ๋‹นํ•œ๋‹ค.

    • ํ…Œ์ŠคํŠธ๋Š” ์ „๋ถ€ ํ†ต๊ณผํ•˜์ง€๋งŒ ๋ชจ๋“  ํƒ€์ž… ์•ˆ์ •์„ฑ์„ ํฌ๊ธฐ.
    • ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ์•”์‹œ์  any๋ฅผ ๋ฐ˜ํ™˜
  • DefinitelyTyped์˜ ํƒ€์ž… ์„ ์–ธ์„ ์œ„ํ•œ ๋„๊ตฌ: dtslint

    • ์ฃผ์„์„ ํ†ตํ•ด ๋™์ž‘ํ•œ๋‹ค.
    • ๊ฐ ์‹ฌ๋ฒŒ์˜ ํƒ€์ž…์„ ์ถ”์ถœํ•˜์—ฌ "๊ธ€์ž ์ž์ฒด"๊ฐ€ ๊ฐ™์€ ์ง€ ๋น„๊ต
      • ํ•œ๊ณ„: ๊ธ€์ž๋งŒ ๋น„๊ตํ•œ๋‹ค. string๊ณผ any, number|string๊ณผ string|number ํ™•์ธ ์–ด๋ ค์›€
    const beatles = ["john", "paul", "george", "ringo"];
    map(
      beatles,
      function (
        name, // $ExpectType string
        i, // $ExpectType number
        array // $ExpectType string[]
      ) {
        this; // $ExpectType string[]
        return name.length;
      }
    ); // $ExpectType number
    

expectTypeOf

  • ํƒ€์ž… ์ผ์น˜ ํ™•์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
import { expectTypeOf } from "expect-type";

const beatles = ["john", "paul", "george", "ringo"];
expectTypeOf(
  map(beatles, function (name, i, array) {
    expectTypeOf(name).toEqualTypeOf<string>();
    expectTypeOf(i).toEqualTypeOf<number>();
    expectTypeOf(array).toEqualTypeOf<string[]>();
    expectTypeOf(this).toEqualTypeOf<string[]>();
    return name.length;
  })
).toEqualTypeOf<number[]>();

Things to Remember

  • When testing types, be aware of the difference between equality and assignability, particularly for function types.
    • ํƒ€์ž… ํ…Œ์ŠคํŠธ ์‹œ, ํ•จ์ˆ˜ ํƒ€์ž…์—์„œ ๋™์ผ์„ฑ(equality)๊ณผ assignability(ํ• ๋‹น ๊ฐ€๋Šฅ์„ฑ)์˜ ์ฐจ์ด์  ์•Œ๊ธฐ
  • For functions that use callbacks, test the inferred types of the callback parameters. Don't forget to test the type of this if it's part of your API.
    • ์ฝœ๋ฐฑ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ํƒ€์ž… ํ…Œ์ŠคํŠธ. API์— this ๊ด€๋ จ ์‚ฌํ•ญ ์žˆ์œผ๋ฉด ํ…Œ์ŠคํŠธ
  • Avoid writing your own type testing code. Use one of the standard tools instead.
    • ์ง์ ‘ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ผ๋ฐ˜ํ™”๋œ ํˆด ์‚ฌ์šฉํ•˜๊ธฐ
  • For code on DefinitelyTyped, use dtslint. For your own code, use vitest, expect-type, or the Type Challenges approach. If you want to test type display, use eslint-plugin-expect-type.
    • DefinitelyTyped์—์„œ๋Š” dtslint ์‚ฌ์šฉ. ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ์ฝ”๋“œ๋ผ๋ฉด ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์ž.
    • ๋„๊ตฌ๋“ค: vitest, expect-type, Type Challenges ์ ‘๊ทผ๋ฒ•, (ํƒ€์ž… ๋””์Šคํ”Œ๋ ˆ์ด)eslint-plugin-expect-type