2024-05-21.md
π‘DIL: μ΄νν°λΈ νμ μ€ν¬λ¦½νΈ
μ€ν°λ: μκ° CS, https://github.com/monthly-cs/2024-05-effective-typescript
μμ±μΌ: 2024-05-21
μμ±μ: dusunax
νμ μ€ν¬λ¦½νΈ
μμ΄ν  19: μΆλ‘ κ°λ₯ νμ μ μ¬μ©ν΄ μ₯ν©ν μ½λ λ°©μ§νκΈ° Avoid Cluttering Your Code with Inferable Types
νμ μΆλ‘
- λͺ¨λ λ³μμ νμ μ μΈνλ κ²μ λΉμμ°μ  / λΆνμ
 
// not good!
let x: number = 12;
// enough!
let x = 12;
- νμ μΆλ‘ μ΄ λλ€λ©΄ λͺ μμ  νμ ꡬ문μ νμνμ§ μμ (μ€νλ € λ°©ν΄)
 - 볡μ‘ν κ°μ²΄ λλ ν¨μμ λ°ν νμ λ μΆλ‘ ν μ μμ
 
// κ°μ²΄ μΆλ‘ 
const person = {
  name: "Sojourner Truth",
  born: {
    where: "Swartekill, NY",
    when: "c.1797",
  },
  died: {
    where: "Battle Creek, MI",
    when: "Nov. 26, 1883",
  },
};
// {
//   name: string;
//   born: {
//     where: string;
//     when: string;
//   };
//   died: {
//     where: string;
//     when: string;
//   }
// }
// ν¨μμ λ°ν νμ
 μΆλ‘ 
function square(nums: number[]) {
  return nums.map((x) => x * x);
}
const squares = square([1, 2, 3, 4]);
//    ^? const squares: number[]
- 
μ λ νμ μΆλ‘ (λ³΄λ€ μ νν νμ μΆλ‘ μ ν΅ν΄ νμ μ€λ₯ λ°©μ§!)
 - 
ꡬ쑰λΆν΄ ν λΉ(λΉκ΅¬μ‘°ν ν λΉ)μ ν΅ν΄ μ§μ λ³μμ νμ μ΄ μΆλ‘ λλλ‘ νμ. (λͺ μμ  νμ μ μΈX)
 
function logProduct(product: Product) {
  const id: number = product.id;
  // ~~ Type 'string' is not assignable to type 'number'
  const name: string = product.name;
  const price: number = product.price;
  console.log(id, name, price);
}
function logProduct(product: Product) {
  const { id, name, price } = product;
  console.log(id, name, price);
}
λ§€κ°λ³μ νμ λͺ μ
- 
νμ μ€ν¬λ¦½νΈλ λ§€κ°λ³μμ μ΅μ’ μ¬μ©μ²κΉμ§ κ³ λ €νμ§ μλλ€
- λ³μμ νμ μ μ²μ λ±μ₯ν λ κ²°μ λλ€
 - ν¨μ/λ©μλ μκ·Έλμ²μ νμ ꡬ문μ ν¬ν¨νκ³ , ν¨μ λ΄μ μ§μ λ³μμλ νμ ꡬ문μ λ£μ§ μκΈ° (μ½λ μ¬λμ΄ κ΅¬ν λ‘μ§μ μ§μ€ν μ μμ)
 
 - 
λ§€κ°λ³μ κΈ°λ³Έκ°μ΄ μλ κ²½μ°, νμ μ μΆλ‘ νλ€
function parseNumber(str: string, base = 10) { // ^? (parameter) base: number // ... } 
νμ μ λ³΄κ° μλ λΌμ΄λΈλ¬λ¦¬
- 
νμ μ§μνλ λΌμ΄λΈλ¬λ¦¬μμ
μ½λ°± ν¨μμ λ§€κ°λ³μ νμμ μλμΌλ‘ μΆλ‘ λλ€(보ν΅)// Don't do this: app.get("/health", (request: express.Request, response: express.Response) => { response.send("OK"); }); // Do this: app.get("/health", (request, response) => { // ^? (parameter) request: Request<...> response.send("OK"); // ^? (parameter) response: Response<...> }); - 
μμ
import _ from "lodash"; interface FoodItem { icon: string; category: string; price: number; } const foodItems: FoodItem[] = [ { icon: "π", category: "Fast Food", price: 5000 }, { icon: "π", category: "Fast Food", price: 8000 }, { icon: "π£", category: "Japanese", price: 12000 }, { icon: "π", category: "Japanese", price: 10000 }, { icon: "π", category: "Italian", price: 15000 }, { icon: "π₯", category: "Healthy", price: 9000 }, ]; // Lodashμ groupByλ₯Ό μ¬μ©ν λ μ½λ°± ν¨μμ λ§€κ°λ³μ νμ μ΄ μλμΌλ‘ μΆλ‘ λ¨ const groupedByCategory = _.groupBy(foodItems, (item) => item.category); console.log(groupedByCategory); 
νμ μ λͺ μνκ³ μΆμ κ²½μ°: κ°μ²΄ 리ν°λ΄ μ μ
- μ μμ νμ
μ λͺ
μνλ©΄, excess property check(μΆκ° μμ± μ²΄ν¬, μμ¬ μμ± μ²΄ν¬)κ° λμνλ€
- μ νμ  μμ±μ΄ μλ νμ μ μ€ν λ±μ μ€λ₯
 - λ³μκ° μ¬μ©λλ μκ°μ΄ μλ ν λΉνλ μμ μ μ€λ₯λ₯Ό νμ
 
 
const elmo: Product = {
  name: "Tickle Me Elmo",
  id: "048188 627152",
  price: 28.99,
};
νμ μ λͺ μνκ³ μΆμ κ²½μ°: ν¨μ λ°νκ°
- νμ
 μΆλ‘ μ΄ κ°λ₯ν μ§λΌλ, ꡬνμμ μ€λ₯κ° ν¨μλ₯Ό νΈμΆν κ³³κΉμ§ μν₯μ λ―ΈμΉμ§ μκΈ° μν΄ νμ
 ꡬ문μ λͺ
μν  μ μλ€.
- μλ Promise μμ μ°Έκ³ (μ€μ λ‘λ async/awaitμ ν¨κ³Όμ μΌλ‘ μ¬μ©νκΈ°, μμ΄ν  25)
 
 
const cache: { [ticker: string]: number } = {};
function getQuote(ticker: string) {
  if (ticker in cache) {
    return cache[ticker]; // ꡬν μ€λ₯: Promiseλ₯Ό λ°νν΄μΌ νλ€!
  }
  return fetch(`https://quotes.example.com/?q=${ticker}`)
    .then((response) => response.json())
    .then((quote) => {
      cache[ticker] = quote;
      return quote as number;
    });
}
// ν¨μλ₯Ό νΈμΆν κ³³μμ μλ¬κ° λ°μνλ€
getQuote("MSFT").then(considerBuying);
//               ~~~~ Property 'then' does not exist on type
//                    'number | Promise<number>'
// μλλ λ°ν νμ
μ λͺ
μνμ¬ => μλ¬κ° λ°μν μμΉλ₯Ό μ νν νκΈ°νκΈ°
const cache: { [ticker: string]: number } = {};
function getQuote(ticker: string): Promise<number> {
  if (ticker in cache) {
    return cache[ticker];
    // ~~~ Type 'number' is not assignable to type 'Promise<number>'
  }
  // ...
}
- 
μ₯μ 
- μ€λ₯μ μμΉλ₯Ό μ λλ‘ νμνλ€
 - ν¨μ μκ·Έλμ²λ₯Ό λμ± λͺ ννκ² νλ€ (μ /μΆλ ₯ νμ λͺ μ)
 - λͺ λͺ λ νμ μ¬μ©νκΈ°
 
interface Vector2D { x: number; y: number; } function add(a: Vector2D, b: Vector2D): Vector2D { return { x: a.x + b.x, y: a.y + b.y }; } 
Things to Remember
- Avoid writing type annotations when TypeScript can infer the same type.
- νμ μ€ν¬λ¦½νΈκ° νμ μ μΆλ‘ ν μ μλ€λ©΄, νμ ꡬ문 μμ±νμ§ μκΈ°
 
 - Ideal TypeScript code has type annotations in function/method signatures but not on local variables in their bodies.
- ν¨μ/λ©μλ μκ·Έλμ²μ νμ ꡬ문μ μμ±νκ³ , λ΄λΆ μ§μ λ³μμλ μμ±νμ§ λ§μ.
 
 - Consider using explicit annotations for object literals to enable excess property checking and ensure errors are reported close to where they occur.
- κ°μ²΄ 리ν°λ΄κ³Ό ν¨μ λ°νμλ νμ λͺ μλ₯Ό κ³ λ €νμ.
 - μΆκ°/μμ¬ μμ± μ²΄ν¬ & μλ¬κ° λ°μν μμΉμ νμλλλ‘ νκΈ°
 
 - Don't annotate function return types unless the function has multiple returns, is part of a public API, or you want it to return a named type.
- 곡κ°λ API ν¨μμ΄κ±°λ, λͺ
λͺ
λ νμ
μ΄ νμν κ²½μ°λ₯Ό μ μΈνκ³  λ¦¬ν΄ νμ
μ λͺ
μνμ§ μμλ λ  κ²
- μλ§λ 컨벀μ μ λ°λ₯Ό κ² κ°λ€
 
 
 - 곡κ°λ API ν¨μμ΄κ±°λ, λͺ
λͺ
λ νμ
μ΄ νμν κ²½μ°λ₯Ό μ μΈνκ³  λ¦¬ν΄ νμ
μ λͺ
μνμ§ μμλ λ  κ²