Frontend/TypeScript

[ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ(TypeScript) ] ์ด์ค‘ ๋ฐ˜๋ณต๋ฌธ์—์„œ ๋ฐ˜๋ณต๋ฌธ ์ˆœํšŒ ํ›„ ํƒ€์ž… ๊ฐ•์ œํ•˜๊ธฐ

YWTechIT 2022. 7. 3. 22:06
728x90

๐Ÿ“ ์ด์ค‘ ๋ฐ˜๋ณต๋ฌธ์—์„œ ๋ฐ˜๋ณต๋ฌธ ์ˆœํšŒ ํ›„ ํƒ€์ž… ๊ฐ•์ œํ•˜๊ธฐ

์–ธ๋œป ์ œ๋ชฉ๋งŒ ๋ด์„œ๋Š” ์ดํ•ดํ•˜๊ธฐ ํž˜๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ, ์‰ฝ๊ฒŒ ๋งํ•ด ํƒ€์ž…์ด 2๊ฐœ ์ด์ƒ์ธ data์—์„œ find๋ฅผ ํ†ตํ•ด ๋‚˜์˜จ ๊ฐ’์— ์›ํ•˜๋Š” property๋งŒ ์ถ”์ถœํ•˜๊ณ  ์‹ถ์„ ๋•Œ ํ•ด๋‹น ํƒ€์ž…์„ assertion ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด๋ฏธ data์— ํƒ€์ž…์ด ์ •ํ•ด์ ธ ์žˆ๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ๊ตณ์ด type assertion ํ•ด์•ผ๋˜๋‚˜?๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, API์š”์ฒญ์„ ํ†ตํ•ด ๋ฐ›์€ ๊ฐ’(data)์˜ ํƒ€์ž…์ด 2๊ฐœ ํ˜น์€ 2๊ฐœ ์ด์ƒ์œผ๋กœ ์„ค์ •๋˜์–ด์žˆ๊ณ , ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ property๊ฐ€ ๊ฐ๊ฐ์˜ ํƒ€์ž…์— ๊ณตํ†ต์œผ๋กœ ๋“ค์–ด์žˆ์ง€ ์•Š์€ property์ธ๋ฐ, ํ•œ์ชฝ ํƒ€์ž…์˜ property๋งŒ ์ถ”์ถœํ•˜๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š” ๊ฒฝ์šฐ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ธ€์„ ์ž‘์„ฑํ–ˆ๋‹ค.

 

ํ•œ ๊ฐ€์ง€ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์‚ดํŽด๋ณด์ž. API๋ฅผ ํ†ตํ•ด ๋ฐ›์€ ๊ฐ’ data ๊ฐ’์ด ์žˆ๊ณ , ๊ทธ data์˜ ํƒ€์ž…์€ data[][]์ด๋‹ค. ์—ฌ๊ธฐ์„œ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๋กœ์ง์€ find๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด type===info์˜ value.text๊ฐ’์„ ์ฐพ๊ณ  type===info์˜ value.text์˜ ๊ฐ’์ด ์—†์œผ๋ฉด Unknown์œผ๋กœ ์ €์žฅํ•˜์—ฌ ๊ฒฐ๊ตญ์—” string []์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋กœ์ง์„ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ๋‹ค.

728x90

๊ทธ๋Ÿฐ๋ฐ, ํ•˜๋‹จ ์ฝ”๋“œ ๋ธ”๋ก์˜ // Bad์ฒ˜๋Ÿผ ์ž‘์„ฑํ•˜๋ฉด ESlint์—์„œ Unsafe assignment ~ ์—๋Ÿฌ๊ฐ€ ๋‚˜์˜ค๋Š” ๋ชจ์Šต์„ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ dataDocument์˜ ํƒ€์ž…์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์•„ any[]์ธ ํƒ€์ž…์œผ๋กœ ์„ค์ •๋˜์–ด ๋‚˜ํƒ€๋‚˜๋Š” ์—๋Ÿฌ์˜€๋‹ค. ๊ทธ๋ž˜์„œ as๋ฅผ ์‚ฌ์šฉํ•ด Not Good์ฒ˜๋Ÿผ ์ž‘์„ฑํ–ˆ์œผ๋‚˜, ์ด๋ฒˆ์—” text property๋ฅผ ์ฐพ์ง€ ๋ชปํ•œ๋‹ค๋Š” ์—๋Ÿฌ์˜€๋‹ค. as๋กœ ๊ฐ•์ œํ•ด์คฌ๋Š”๋ฐ ์™œ ์ €๋Ÿฐ ์—๋Ÿฌ๊ฐ€ ์ƒ๊ธฐ์ง€..?๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉฐ 30๋ถ„์˜ ์‚ฝ์งˆ ๊ฒฐ๊ณผ ์–ป์€ ๊ฒƒ์€ find ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋‚˜์˜จ ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด ํƒ€์ž…์„ InfoType์œผ๋กœ ๊ฐ•์ œํ•ด์ค˜์•ผ find ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋‚˜์˜จ ๊ฒฐ๊ณผ๋Š” ๋ชจ๋‘ InfoType์ด๊ณ , InfoType ๋‚ด๋ถ€์— ์žˆ๋Š” value.text์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ์Œ์„ ๊นจ๋‹ฌ์•˜๋‹ค. ์ด์ „ ๋‹จ๊ณ„์— assertion์„ ํ•ด์•ผํ•œ๋‹ค๋Š” ์ƒ๊ฐํ•˜์ง€ ๋ชปํ•˜๊ณ  ์ตœ์ข…๋‹จ๊ณ„์ธ value.text ๊ฐ’์— assertionํ•˜์—ฌ ์ƒ๊ธด ๋ฌธ์ œ์˜€์—ˆ๋‹ค! Good์ฒ˜๋Ÿผ ์ž‘์„ฑํ•˜๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์˜ต์…”๋„ ์ฒด์ด๋‹(?)์„ ๋นผ๋„ ๋˜๋ฏ€๋กœ ํ•œ์ธต ๊ฐ€๋…์„ฑ์ด ๋†’์•„์ง„ ์ฝ”๋“œ๊ฐ€ ๋˜์—ˆ๋‹ค. ๋‚˜์™€ ๊ฐ™์€ ๋ฌธ์ œ๋กœ ๊ณ ์ƒํ•˜๋Š” ๋ถ„๋“ค์—๊ฒŒ ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ํ•˜๋Š” ๋ฐ”๋žŒ์œผ๋กœ ๊ธ€์„ ๋งˆ์นœ๋‹ค.

 

 

22. 7. 5. ํ™”.
typescript์˜ ์‚ฌ์šฉ์ž-์ •์˜ ํƒ€์ž… ๊ฐ€๋“œ(User-Defined Type Guards)์ธ is ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํƒ€์ž…๊ฐ€๋“œ๋ž€, ์Šค์ฝ”ํ”„ ์•ˆ์—์„œ์˜ ํƒ€์ž…์„ ๋ณด์žฅํ•˜๋Š” ๋Ÿฐํƒ€์ž„ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค๋Š” ํ‘œํ˜„์‹์ด๋‹ค. Use TypeGuard์ฝ”๋“œ์—์„œ document is InfoType์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ document์˜ ํƒ€์ž…์˜ ๋ฒ”์œ„๋ฅผ InfoType ๋กœ ์ถ•์†Œ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. (ํ”ผ๋“œ๋ฐฑ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋””๋ฐ๋ธŒ๋‹˜ :))

// type.ts
interface InfoType {
  type: 'info'
  value: {
    text: string
  }
}

interface ImageType {
  type: 'images'
  value: {
    id: string
    source?: object
  }
}

type Data = InfoType | ImageType

// index.tsx
const data: Data[][] = [  
  [
    { type: "info", value: [Object] },
    { type: "images", value: [Object] },
  ],
  [
    { type: "info", value: [Object] },
    { type: "images", value: [Object] },
  ],
  [
    { type: "info", value: [Object] },
    { type: "images", value: [Object] },
  ],
  [
    { type: "info", value: [Object] },
    { type: "images", value: [Object] },
  ],
];

// Bad
const infoTextLabels: string[] = data.map(
  (dataDocument) =>
    dataDocument.find(({ type }) => type === 'info')?.value.text ||
    'Unknown',
)

// Not Bad
 const infoTextLabels: string[] = data.map(
    (dataDocument) =>
      (dataDocument.find(({ type }) => type === 'info')?.value
        .text as InfoType['value']['text']) || 'Unknown',
  )

// Good
const infoTextLabels: string[] = data
  .map(
    (dataDocument) =>
      (
        dataDocument.find(
          ({ type }) => type === 'info',
        ) as InfoType
      ).value.text || 'Unknown',
  )

// Use TypeGuard
const tabLabels = entries
  .map(
    (embeddedDocument) =>
      embeddedDocument.find(
        (document): document is InfoType =>
          document.type === 'info',
      )?.value.text || 'Unknown',
  )
๋ฐ˜์‘ํ˜•