๐Ÿ—ฃ๏ธ ์ด ๊ธ€์€ ์•„๋ž˜ ๊ธ€์˜ ๋ฒˆ์—ญ๊ธ€์ž…๋‹ˆ๋‹ค.

 

https://blog.logrocket.com/typescript-vs-flow-vs-proptypes/

 

Comparing statically typed JavaScript implementations - LogRocket Blog

In this post, we'll compare three of the most popular ways of imposing static typing on JavaScript: TypeScript, Flow, and PropTypes.

blog.logrocket.com

 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋ณ€์ˆ˜์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์—์„œ ๊ทธ ๋ณ€์ˆ˜์— ์˜ํ•ด ๊ฒฐ์ •๋˜๊ณ , ํ”„๋กœ๊ทธ๋žจ์„ ํ†ตํ•ด ์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ๊ทธ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•  ๊ฒฝ์šฐ์—๋„ ๋ณ€ํ•  ์ˆ˜ ์žˆ๋Š” ๋™์  ํƒ€์ž… ์–ธ์–ด(Dynamically typed language)์ด๋‹ค.

 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—๋Š” ๋ณ€์ˆ˜์˜ ํƒ€์ž…์„ ์ œํ•œํ•˜๊ฑฐ๋‚˜ ์ฃผ์„ ์ฒ˜๋ฆฌํ•  ๋ฐฉ๋ฒ•์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ• ๋•Œ ๋ณ€์ˆ˜๊ฐ€ ๊ฐ€์ ธ์•ผ ํ•˜๋Š” ํƒ€์ž…์— ๋Œ€ํ•ด ๊ณ ๋ฏผ์„ ๋งŽ์ด ํ•˜๋Š” ๊ฒƒ์„ ๋œ์–ด์ฃผ๊ณ  ์กฐ๊ธˆ ๋” ๋น ๋ฅด๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์ง€๋งŒ, ์ด ๋ง์€ ๋˜ํ•œ ์šฐ๋ฆฌ์˜ ํ”„๋กœ๊ทธ๋žจ์ด ๋ฒ„๊ทธ๋ฅผ ๊ฐ–๊ฑฐ๋‚˜ ๋ณ€์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ํƒ€์ž…์ด ๋˜์–ด ์˜ˆ๊ธฐ์น˜ ๋ชปํ•œ ํ–‰๋™์„ ์œ ๋ฐœํ•  ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๋œป์ด๊ธฐ๋„ ํ•˜๋‹ค.

 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ด๋Ÿฌํ•œ ๋™์  ํƒ€์ดํ•‘์˜ ๋ฌธ์ œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์ž‘์„ฑํ•˜๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ํŠธ๋žœ์ŠคํŒŒ์ผ ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋ณ€์ˆ˜๋ฅผ ์—„๊ฒฉํ•˜๊ฒŒ ํ™•์ธํ•˜๊ณ  ์ œ์–ดํ•˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํƒ€์ž… ์ต์Šคํ…์…˜์ด ํ•„์š”ํ•˜๋‹ค.

 

์—ฌ๊ธฐ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ •์  ํƒ€์ž… ์ต์Šคํ…์…˜์„ ์ œ๊ณตํ•˜๋Š” ๋งŽ์€ ์–ธ์–ด๋“ค์ด ์žˆ๋‹ค.

 

์ด ๊ธ€์€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ, Flow, Prop Types์— ์ดˆ์ ์„ ๋งž์ถ”๊ณ  ์ด ์–ธ์–ด๋“ค์˜ ๊ธฐ๋Šฅ๊ณผ ๋Šฅ๋ ฅ์„ ๋น„๊ตํ•œ๋‹ค.

 

โœฃ Type-Checkiing ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ / ์–ธ์–ด ๋น„๊ตํ•˜๊ธฐ

  Typescript Flow Prop Types
๊ฐœ๋ฐœ์ž Microsoft Facebook Facebook
๋ฆด๋ฆฌ์ฆˆ 2012.10.1 2014.11.18 2017.4.8
๋ผ์ด์„ผ์Šค ์˜คํ”ˆ์†Œ์Šค MIT MIT
์ปค๋ฎค๋‹ˆํ‹ฐ ํผ ์ž‘์Œ ์ƒ๋Œ€์ ์œผ๋กœ ์ž‘์Œ
Dependencies
Performace ๊ฐ€์žฅ ๋น ๋ฅด๊ณ  ๋ฒ„๊ทธ๊ฐ€ ์ ๋‹ค ์ผ๋ถ€ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ณด๊ณ ๋จ. Flow ํŒ€์€ 2019๋…„์— ์žฌ๊ฒ€์‚ฌ ์‹œ๊ฐ„๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๊ฐ์†Œํ–ˆ๋‹ค๊ณ  ๋ณด๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ณด๊ณ ๋˜์ง€ ์•Š์€ ์„ฑ๋Šฅ ํ†ต๊ณ„
ํƒ€์ž… ์ฒดํฌ
(type checking)
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํƒ€์ž…, ์ œ๋„ค๋ฆญ ํƒ€์ž… ์ •์˜, ์„ ํƒ์  nullable ํƒ€์ž… ์‚ฌ์šฉ ์•„๋งˆ๋„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํƒ€์ž…, ์ œ๋„ค๋ฆญ ํƒ€์ž… ์ •์˜, ์„ ํƒ์  nullable ํƒ€์ž… ์‚ฌ์šฉ ์ž์ฒด ํƒ€์ž… ์œ ํšจ์„ฑ ๊ฐ์ฒด ์‚ฌ์šฉ
ํƒ€์ž… ์บ์ŠคํŒ…
(type casting)
as ํ‚ค์›Œ๋“œ ์‚ฌ์šฉ : ์‹ฌ๋ณผ ์‚ฌ์šฉ N/A
interfaces, enums, ์ปค์Šคํ…€ ํƒ€์ž… ๊ฐ์ฒด ์ง€์› interfaces, enums, ์ปค์Šคํ…€ ํƒ€์ž… ๊ฐ์ฒด ์ง€์› interfaces, enums, ์ธํ„ฐํŽ˜์ด์Šค์™€ enum์œผ๋กœ ํ‚ค์›Œ๋“œ ์„ ์–ธ๋จ ์ž์ฒด ์˜ต์…˜์„ ์‚ฌ์šฉํ•œ enum, PropTyps.oneOf([...]) ์ง€์›
ํ…์ŠคํŠธ ์—๋””ํ„ฐ ์ง€์› IntelliSense(์ž๋™ ์™„์„ฑ), ์ •์˜๋กœ ์ด๋™, ์˜ค๋ฅ˜/๊ฒฝ๊ณ  ๋“ฑ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ํŽธ์ง‘๊ธฐ/IDE์— ๋Œ€ํ•œ ๋Œ€๊ทœ๋ชจ ์ง€์› IntelliSense(์ž๋™ ์™„์„ฑ), ์ •์˜๋กœ ์ด๋™, ์˜ค๋ฅ˜/๊ฒฝ๊ณ  ๋“ฑ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ํŽธ์ง‘๊ธฐ/IDE์— ๋Œ€ํ•œ ๋Œ€๊ทœ๋ชจ ์ง€์› ์ปดํฌ๋„ŒํŠธ propTypes์„ ์ž๋™ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ Visual studio code, Webstorm์˜ ์ œํ•œ๋œ ์ง€์›
Resources and Documentation
์ปค๋ฎคํ‹ฐ๋‹ˆ์™€ ํ”„๋กœ์ ํŠธ ์ง€์› Nest.js๋ฅผ ํฌํ•จํ•˜์—ฌ Vue, React, Angular, Express ๋“ฑ ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—ฌ๋Ÿฌ ํ”„๋ ˆ์ž„์›Œํฌ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ง€์› ๋ฐ”๋ฒจ์„ ํ†ตํ•ด ํ”„๋กœ์ ํŠธ์— ์„ค์น˜ ๊ฐ€๋Šฅ, ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์œผ๋กœ React์™€ ์‚ฌ์šฉ ์ฃผ๋กœ React์™€ ์‚ฌ์šฉ๋˜์ง€๋งŒ PropTypes.checkPropTypes๋ฅผ ํ˜ธ์ถœํ•ด ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์‚ฌ์šฉ๊ฐ€๋Šฅ
์ปดํŒŒ์ผ๋Ÿฌ ์—๋Ÿฌ ๊ฐ์ง€ IDE์™€ ํ…์ŠคํŠธ์—๋””ํ„ฐ์—์„œ ๊ฐ€๋Šฅ ์ง€์›๋˜๋Š” IDE์™€ ํ…์ŠคํŠธ์—๋””ํ„ฐ์—์„œ ๊ฐ€๋Šฅ ์‚ฌ์šฉ ๋ถˆ๊ฐ€
Syntax ๊ด‘๋ฒ”์œ„ํ•œ ํƒ€์ž… ์ฒดํ‚น, ์ •์  ๋™์  ํƒ€์ž… ํฌํ•จ ๊ด‘๋ฒ”์œ„ํ•œ ํƒ€์ž… ์ฒดํ‚น, ์ •์  ๋™์  ํƒ€์ž… ํฌํ•จ PropTypes ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•œ ์˜์กด
์ œ๋„ˆ๋ฆญ(Generics) ์ง€์›๋จ ์ง€์›๋จ ์ง€์› ์•ˆ ๋จ
๊ธฐ์กด ํ”„๋กœ์ ํŠธ ์ง€์› ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ ๊ฐ€๋Šฅ ๋ฐ”๋ฒจ๊ณผ ํ•จ๊ป˜ ์ง€์› ๊ฐ€๋Šฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜์™€ PropTypes.checkPropTypes ์ˆ˜๋™ ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ง€์›

 

 

์ด ๊ธ€์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ™•์žฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ/์–ธ์–ด์˜ ๊ธฐ์ˆ ๊ณผ ๋Šฅ๋ ฅ์„ ๋น„๊ตํ•˜๊ณ  ๋Œ€์กฐํ•  ๊ฒƒ์ด๋‹ค.

 

์œ ์‚ฌ์ ๊ณผ ์ฐจ์ด์ ์„ ํƒ์ƒ‰ํ•  ๋•Œ ๋จผ์ € ์ฃผ๋ชฉํ•ด์•ผ ํ•  ์ค‘์š”ํ•œ ์ฐจ์ด์ ์€ TypeScript์™€ ๋‹ฌ๋ฆฌ Flow ๋ฐ PropTypes๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ด๋‹ค. Flow์™€ Prop Types๋Š” ์˜ค์ง ์ •์  ํƒ€์ž… ์ฒดํ‚น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋ฉฐ ์ฐจ์ด์ ์€ ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์‚ฌ์šฉ์„ ์ง€์›ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.

 

โš™๏ธ ํ”„๋กœ์ ํŠธ์— ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์„ค์น˜ํ•˜๊ธฐ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ด ๊ธ€์—์„œ ๋น„๊ตํ•œ ์„ธ ๊ฐ€์ง€ ๊ธฐ์ˆ ์ค‘ ๊ฐ€์žฅ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ Vue, Angular ๋˜๋Š” React์—์„œ ์ฆ‰์‹œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์‰ฝ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด, ์šฐ๋ฆฌ๋Š” Typescript์™€ ํ•จ๊ป˜ Vue๋ฅผ ์„ค์น˜ํ• ๋•Œ Vue CLI์—์„œ ๋‚ด์žฅ๋œ Typescript ์˜ต์…˜์„ ์„ ํƒํ•ด ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค. Typescipt๋ฅผ ์„ ํƒํ•˜๋ฉด ์šฐ๋ฆฌ๋Š” tsconfig.json ํŒŒ์ผ(๋ณดํ†ต ๋ธŒ๋ผ์šฐ์ €์˜ ์ตœ๋Œ€ ์ง€์›์„ ์œ„ํ•ด ECMAScript 2009 ์„ค์ •)์—์„œ Javascript๋กœ ํŠธ๋žœ์ŠคํŒŒ์ผํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ์„ฑ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

    // tsconfig.json
    {
      "compilerOptions": {
        // Vue์˜ ๋ธŒ๋ผ์šฐ์ € ์ง€์›์„ ์œ„ํ•ด
        "target": "es5",
        // ์ด๋ฅผ ํ†ตํ•ด 'this'์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ์†์„ฑ์„ ์—„๊ฒฉํ•˜๊ฒŒ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Œ
        "strict": true,
        // webpack 2+ ๋˜๋Š” rollup์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํŠธ๋ฆฌ ์‰์ดํ‚น์„ ํ™œ์šฉํ•˜๋ ค๋ฉด ์•„๋ž˜๋ฅผ ์ž…๋ ฅ
        "module": "es2015",
        "moduleResolution": "node"
      }
    }

 

๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ์‹œ Vue๋ฅผ ์ฐธ์กฐํ•˜๋ฉด Typescript ํƒ€์ž… ์ถ”๋ก ์„ ์–ป๊ฒŒ ๋œ๋‹ค.

 

    
    import Vue from 'vue'

    const Component = Vue.extend({
      // ...
    })

 

๋˜ํ•œ Vue๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ ์œ ํ•œ ํŠน๋ณ„ํ•œ ๋ฐฉ์‹์œผ๋กœ Typescript๋ฅผ ์‚ฌ์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

 

    
    <template>
      <button @click="onClick">Click!</button>
    </template>


    <script lang="ts">
        import * as Vue from "vue";
        import { Component } from "vue-property-decorator";

        @Component()
        class App extends Vue {
          public message: string = "Hello World";

          public onClick(): void {
            window.alert(this.message);
          }
        }

        export default App;
    </script>

 

์—ฌ๊ธฐ์„œ ์ผ๋ถ€ Typescript ์–ด๋…ธํ…Œ์ด์…˜๊ณผ ํ•จ๊ป˜ Javascript ์นœํ™”์ ์ธ ๊ตฌ๋ฌธ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Angular๋Š” Typescript์™€ ํ•จ๊ป˜ ์„ค์น˜๋˜๊ณ  Typescript๋ฅผ ๊ฑฐ์˜ ๋…์ ์ ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ํ•œ๋•Œ Angular ์•ฑ์„ ์ˆœ์ˆ˜ Javascript๋กœ ์ž‘์„ฑํ•˜๋Š” ์˜ต์…˜์ด ์žˆ์—ˆ๋Š”๋ฐ ์ธ๊ธฐ๋ฅผ ๋Œ์ง€๋Š” ๋ชปํ–ˆ๋‹ค.

 

โš™๏ธ ํ”„๋กœ์ ํŠธ์— Flow ์„ค์น˜ํ•˜๊ธฐ

๋ฐ˜๋ฉด์—, Babel ๊ตฌ์„ฑ์— Flow ์ง€์›์„ ํ™œ์„ฑํ™”ํ•ด ํ”„๋กœ์ ํŠธ์— Flow๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

Flow๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

 

npm install --save-dev @babel/preset-flow

 

๊ทธ๋ฆฌ๊ณ  .babelrc์— ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.


    {
      "presets": ["@babel/preset-flow"]
    }

 

โš™๏ธ ํ”„๋กœ์ ํŠธ์— PropTypes ์„ค์น˜ํ•˜๊ธฐ

ํ”„๋กœ์ ํŠธ์— PropTypes๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด PropTypes ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์ปดํฌ๋„ŒํŠธ์˜ prop types๋ฅผ ์ •์˜ํ•˜๊ณ  PropTypes.checkPropTypes์„ ํ˜ธ์ถœํ•œ๋‹ค.

 

Prop Types๋ฅผ ์„ค์น˜ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

 

npm install --save prop-types

 

๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ปดํฌ๋„ŒํŠธ์˜ prop type ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ์ •์˜ํ•˜๊ณ  ํ”„๋กœํผํ‹ฐ์™€ values ๊ฐ์ฒด๋ฅผ ์„ค์ •ํ•œ๋‹ค.

 

    
    const myPropTypes = {
      name: PropTypes.string,
      age: PropTypes.number,
      // ... prop types ๊ฒ€์ฆ์„ ์ •์˜ํ•œ๋‹ค
    };

    const props = {
      name: 'hello', // ์œ ํšจ
      age: 'world', // ์œ ํšจํ•˜์ง€ ์•Š์Œ
    };

 

๊ทธ๋ฆฌ๊ณ  Prop Type์„ ์ฒดํฌํ•œ๋‹ค.

 

   
   	// 'MyComponent' ์ปดํฌ๋„ŒํŠธ๋กœ ์ •์˜ํ•œ๋‹ค

    // Works with standalone PropTypes
    PropTypes.checkPropTypes(myPropTypes, props, 'age', 'MyComponent');

    // ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค
    // Warning: Failed prop type: Invalid prop `age` of type `string` supplied to
    // `MyComponent`, expected `number`.

 

ํƒ€์ž… ์ •์˜์™€ ๊ตฌ๋ฌธ ์ฒดํฌ

 

์•ž์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์„ธ ๊ฐ€์ง€ ๊ธฐ์ˆ  ๋ชจ๋‘ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ํƒ€์ž… ์ฒดํฌ ๋ฐ ์ œํ•œ์„ ์ œ๊ณตํ•˜๋ฉฐ ์ด๊ฒƒ๋“ค์„ ๋น„๊ตํ•ด ๋ณด๋ ค ํ•œ๋‹ค.

 

๐Ÿ› ๏ธ Flow์™€ Typescript์˜ ํƒ€์ž… ์ •์˜

Flow์™€ Typescript๋Š” ์ƒ๋‹นํžˆ ์œ ์‚ฌํ•œ ํƒ€์ž… ์ •์˜ ๊ตฌ๋ฌธ์„ ๊ฐ–๊ณ  ์žˆ๋‹ค.

 

๊ณตํ†ต์ :

  • ๋ณ€์ˆ˜ ํƒ€์ž… ์ฒดํฌ์— ๋Œ€ํ•œ Javascript ์›์‹œ ํƒ€์ž…๊ณผ ํŒŒ์ƒ(๊ฐ์ฒด)๋œ ํƒ€์ž…์„ ์ œ๊ณต
  • ์œ ์‚ฌํ•œ ํƒ€์ž… ์–ด๋…ธํ…Œ์ด์…˜ ๊ตฌ๋ฌธ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Œ
  •  ์—ฐ์‚ฐ์ž์™€ ๋‹ค์–‘ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์—ฌ Javascript ํƒ€์ž… ์‹œ์Šคํ…œ์˜ ์œ ์—ฐ์„ฑ์„ ์œ ์ง€
  • ์„ ํƒ์  ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•œ ํƒ€์ž…, ์ฆ‰ Typescript๋Š” nullable ํƒ€์ž…์ด ์žˆ๊ณ  Flow์—๋Š” maybe ํƒ€์ž…์ด ์žˆ์Œ
  • ๋ณ€์ˆ˜ ํƒ€์ž…์„ ๊ฐ–๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ์ œ๋„ˆ๋ฆญ์ด ์žˆ์Œ

 

๋งˆ์ง€๋ง‰ ๊ณตํ†ต์ ์˜ ์˜ˆ์‹œ๋Š” ์•„๋ž˜์— ์žˆ๋‹ค.

function identity<T>(value: T): T {
    return value
}

 

์ œ๋„ค๋ฆญ์€ ๋‹ค๋ฅธ ํƒ€์ž…๋“ค๋กœ ๋ฎ์–ด ์”Œ์—ฌ์งˆ ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜ ํƒ€์ž…์„ ๊ฐ€์ง„๋‹ค :

identity<string>('foo').

 

๋˜ํ•œ ๋‹ค์Œ ์ฝ”๋“œ๋Š” Typescript์™€ Flow์—์„œ ๋™์ผํ•˜๋‹ค. ์—ฌ๊ธฐ์„œ ํ•จ์ˆ˜ concat์€ ๋ฌธ์ž ์œ ํ˜•์ธ ๋‘ ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ๋‘˜์˜ ํ•ฉ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 


    function concat(a: string, b: string) {
      return a + b;
    }

 

๐Ÿ› ๏ธ PropTypes์˜ ํƒ€์ž… ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ

๋ฐ˜๋ฉด์— PropTypes๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ํ”„๋กœํผํ‹ฐ ์„ค์ •์„ ์œ„ํ•ด ์ž์ฒด ํƒ€์ž… ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ฆ‰, PropTypes์—์„œ๋Š” PropTypes ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด ํƒ€์ž…์„ ์ •์˜ํ•œ๋‹ค.

 

    
    import React from 'react';
    import PropTypes from 'prop-types'

    class MyComponent extends React.Component {
      render() {
        // ... do things with the props
      }
    }

    MyComponent.propTypes = {
      optionalArray: PropTypes.array,
    ...

 

๐Ÿ› ๏ธ ํƒ€์ž… ์บ์ŠคํŒ…

Flow์™€ Typescript ๋ชจ๋‘ ๋ณ€์ˆ˜๋ฅผ ํ•œ ํƒ€์ž…์—์„œ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์บ์ŠคํŒ…ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

 

Flow์—์„œ๋Š” ๊ธฐํ˜ธ : ๋ฅผ ์‚ฌ์šฉํ•ด ์บ์ŠคํŒ…ํ•˜๊ณ  Typescript์—์„œ๋Š” as ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์บ์ŠคํŒ…ํ•œ๋‹ค.

 

    
    // TypeScript
    let value = 1 as number;

    // Flow
    let value = 1;
    (value: number);

 

PropTypes๋Š” ํ•œ ํƒ€์ž…์—์„œ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์บ์ŠคํŒ…ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

๐Ÿ› ๏ธ Interfaces, enums, ์ปค์Šคํ…€ ํƒ€์ž…

Interface๋Š” ๊ฐ์ฒด์˜ ๊ตฌ์กฐ์™€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ œํ•œํ•˜๋Š” ํƒ€์ž… ์ •์˜์ด๋‹ค. Enums๋Š” ์—ด๊ฑฐ๋œ ๊ฐ’๋“ค์ด๋ฉฐ ๋ณ€์ˆ˜๋ฅผ enum ๊ฐ’ ์ค‘ ํ•˜๋‚˜๋กœ ์ œํ•œํ•ด ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Flow, TypeScript ๋ฐ PropTypes๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปค์Šคํ…€ ํƒ€์ž… ์ œํ•œ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Flow์™€ TypeScript๋Š” interface ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ปค์Šคํ…€ ํƒ€์ž… ๊ฐ์ฒด๋ฅผ ์ •์˜ํ•œ๋‹ค. ๋ชจ๋‘ implements ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ํด๋ž˜์Šค๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌ์กฐ๋ฅผ ์ƒ์†ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.  ์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด์ž.

 

    
    interface PersonInterface {
      firstName: string;
      lastName: string;
      fullName(firstName: string, lastName: string): string
    }

    class Person implements PersonInterface {
        firstName: string;
        lastName: string;
        constructor(firstName: string, lastName: string){
            this.firstName = firstName;
            this.lastName = lastName;
        }

        fullName(firstName: string, lastName: string): string {
            return `${firstName} ${lastName}`;
        }
    }

 

๋งŒ์•ฝ ์ธํ„ฐํŽ˜์ด์Šค์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐ’์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์œผ๋ฉด Flow์™€ Typescript๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ด๋‹ค.

 

Flow์™€ Typescript ๋˜ํ•œ ํƒ€์ž… ์ฒดํ‚น์„ ์œ„ํ•ด enum ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด  enum ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •์˜ํ•œ๋‹ค.

 

enum Status {
  Active,
  Paused,
  Off,
}

const status: Status = Status.Active //์ผ์น˜
const wrongStatus: Status = 'test' //๋ถˆ์ผ์น˜, ์ •์˜๋œ ํƒ€์ž…์„ ๋”ฐ๋ฅด์ง€ ์•Š์Œ

 

ํ•œ ๊ฐ€์ง€ ๋…ํŠนํ•œ Flow์˜ ํŠน์ง•์€ ํƒ€์ž… ์ฒดํ‚น ์ฝ”๋“œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ฃผ์„์— ์“ด๋‹ค๋Š” ์ ์ด๋‹ค.

function greet(greeting /*: string*/) /* : string */ {
  return greeting;
}

 

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ์ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ฃผ์„์—๋Š” ์ž๋™์™„์„ฑ ๋˜๋Š” ๊ตฌ๋ฌธ ํ•˜์ด๋ผ์ดํŠธ ๊ธฐ๋Šฅ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Š” ํฐ ์žฅ์ ์ด ์•„๋‹ˆ๋‹ค.

 

๋ฐ˜๋ฉด์— PropTypes์€ ์•„๋ž˜์™€ ๊ฐ™์ด PropTypes.oneof๋ฅผ ์‚ฌ์šฉํ•ด enum ํƒ€์ดํ•‘์„ ์ •์˜ํ•œ๋‹ค. 

 

...
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
...

 

PropTypes๋Š” ๋˜ํ•œ PropTypes.shape์„ ์ด์šฉํ•ด ๊ฐ์ฒด ํƒ€์ž… ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•œ๋‹ค.

 

...
optionalObjectWithShape: PropTypes.shape({
    optionalProperty: PropTypes.string,
    requiredProperty: PropTypes.number.isRequired
}),
...

 

๐Ÿ”ง ํ…์ŠคํŠธ ์—๋””ํ„ฐ ์ง€์›

 

Flow์™€ Typescript ๋ชจ๋‘ Visual Studio Code์™€ Sublime๊ณผ ๊ฐ™์€ ์—๋””ํ„ฐ๊ฐ€ ์ง€์›ํ•˜๋Š” ๋‚ด์žฅ๋œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ง€์›์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

 

Flow์™€ TypeScript์— ๋Œ€ํ•œ ์—๋””ํ„ฐ ์ง€์›์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

  • IntelliSense (์ž๋™์™„์„ฑ)
  • Go to Definition(์ •์˜๋กœ ์ด๋™) / Peek Definition (์ •์˜ ๋ณด๊ธฐ)
  • Diagnostics(์ง„๋‹จ) (Errors, Warnings)
  • ํƒ€์ž… ์ •๋ณด hover
  • ์ „ํ™˜ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ ์ ์šฉ ๋ฒ”์œ„ ๋ฆฌํฌํŠธ

Babel์„ ํ†ตํ•ด ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์— Flow ์„ค์น˜๋ฅผ ์ง€์›ํ•˜๋Š” ๋ฌธ์„œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. Flow ์ง€์› ๋ฐ TypeScript ์—๋””ํ„ฐ ์ง€์›์„ ์œ„ํ•œ ์—๋””ํ„ฐ/IDE ์„ค์น˜์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์„ธ์š”.

 

PropTypes ๋˜ํ•œ ํ• ๋‹น๋œ ๊ฐ’์— ๋Œ€ํ•ด ์ปดํฌ๋„ŒํŠธ์˜ prop types์„ ์ž๋™ ์ƒ์„ฑํ•ด์ฃผ๋Š” Visual Studiio code ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค.

 

PropTypes์—๋Š” PropTypes.checkPropTypes๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค(React์—์„œ๋Š” ์ž๋™์œผ๋กœ ํ˜ธ์ถœ๋จ). PropTypes์˜ ๊ณต์‹ ๋ฌธ์„œ์—๋Š” ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ง€์›์— ๋Œ€ํ•œ ์–ธ๊ธ‰์ด ์žˆ์ง€๋งŒ, ์ด๊ฒƒ์ด ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์™ธ๋ถ€ ๋ฌธ์„œ๋Š” ๋งŽ์ง€ ์•Š๋‹ค.

 

๐Ÿ”ง ํšจ์œจ์„ฑ๊ณผ ์„ฑ๋Šฅ

Flow๊ณผ Typescript์˜ ์„ฑ๋Šฅ์˜ ์ฐจ์ด๋Š” ์ž‘๋‹ค. TypeScript๋Š” ์ง€์†์ ์œผ๋กœ 500-600MB์˜ RAM์„ ์‚ฌ์šฉํ•˜๋ฉฐ Flow๋„ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค. ์ปดํ“จํŒ… ์ž์›์˜ ํšจ์œจ์„ฑ ์ธก๋ฉด์—์„œ๋Š” ๋‘˜ ์‚ฌ์ด์— ํฐ ์ฐจ์ด๊ฐ€ ์—†๋‹ค.

 

PropTypes์˜ ํšจ์œจ์„ฑ? ์ด Reddit ์Šค๋ ˆ๋“œ์— ๋”ฐ๋ฅด๋ฉด TypeScript๋Š” ๋” ๋น ๋ฅด๊ณ  ๋ฒ„๊ทธ๊ฐ€ ์ ๋‹ค. 

 

๐Ÿ‘ฅ  ์ปค๋ฎค๋‹ˆํ‹ฐ ์ง€์›

TypeScript์˜ ์ปค๋ฎค๋‹ˆํ‹ฐ๋Š” Flow ๋ฐ PropTypes๊ณผ ๋น„๊ตํ•˜๋ฉด ๊ฐ€์žฅ ํฌ๋‹ค. Flow์™€ PropTypes๋Š” ์ด์ „์— ๋งํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๊ณต์‹ ์†Œ์Šค๋ฅผ ์ œ์™ธํ•˜๋ฉด ๋ฌธ์„œ๊ฐ€ ์ ๊ณ  StackOverflow์˜ ์งˆ๋ฌธ๋„ ์ ๋‹ค. 

 

Vue, Angular ๋ฐ React ๊ฐ™์€ ๋งŽ์€ ํ”„๋ก ํŠธ์—”๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ํ”„๋ ˆ์ž„์›Œํฌ ๋ฐ ํ”Œ๋žซํผ์—๋Š” TypeScript์— ๋Œ€ํ•œ ์ง€์›์ด ๋‚ด์žฅ๋˜์–ด ์žˆ๋‹ค. Express์™€ ๊ฐ™์€ Node.js ์›น ํ”„๋ ˆ์ž„์›Œํฌ์— TypeScript๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ Nest.js๋Š” TypeScript๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ๋Š” ์ƒํƒœ๋กœ ๊ตฌ์ถ•๋˜์–ด ํ”„๋กœ์ ํŠธ๋ฅผ ํฌ๊ฒŒ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  TypeScript๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Express์—์„œ TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ TypeScript ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ๋ฅผ ์„ค์น˜ํ•˜๋ฉด ๋œ๋‹ค.

 

npm install --save-dev typescript

 

๊ทธ๋Ÿฐ ๋‹ค์Œ tsconfig.json ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜์—ฌ TypeScript ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

 

{
    "compilerOptions": {
        "module": "commonjs",
        "esModuleInterop": true,
        "target": "es6",
        "noImplicitAny": true,
        "moduleResolution": "node",
        "sourceMap": true,
        "outDir": "dist",
        "baseUrl": ".",
        "paths": {
            "*": [
                "node_modules/*"
            ]
        }
    },
    "include": [
        "src/**/*"
    ]
}

 

 

Express ๋ฐ Node์— ๋Œ€ํ•œ ํƒ€์ž… ์ •์˜๋ฅผ ์„ค์น˜ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์‹คํ–‰ํ•œ๋‹ค.

npm install --save-dev @types/node @types/express

 

๋ณด๋‹ค์‹œํ”ผ, ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋Œ€ํ•ด TypeScript ํƒ€์ž… ์ •์˜๊ฐ€ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š๋‹ค. TypeScript์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ํƒ€์ž… ์ •์˜๋ฅผ ๋ณด๋ ค๋ฉด ํ™•์‹คํžˆ ํƒ€์ž…์ด ์ง€์ •๋œ ์›น ์‚ฌ์ดํŠธ๋กœ ์ด๋™ํ•ด ๋ณด๋ฉด ๋œ๋‹ค.

 

๐Ÿ“„ ๋ฆฌ์†Œ์Šค์™€ ๋ฌธ์„œ

 

TypeScript๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฆฌ์†Œ์Šค ๋ฐ ๋ฌธ์„œ์˜ ์–‘ ์ธก๋ฉด์—์„œ ํ™•์‹คํžˆ ๋‹ค๋ฅธ ์ •์  ํƒ€์ž… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ณด๋‹ค ๊ฒฝ์Ÿ๋ ฅ์ด ์žˆ๋‹ค.
TypeScript๋Š” ๋‹ค์Œ์„ ์ œ๊ณตํ•œ๋‹ค:

 

์ถ”๊ฐ€ ์ด์ ์œผ๋กœ TypeScript์˜ ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ๋Š” ๋‹ค์–‘ํ•œ ๋ฒ„์ „์˜ TypeScript๋ฅผ ์ง€์›ํ•˜๋ฏ€๋กœ ๋‹ค์–‘ํ•œ ๋ฒ„์ „์˜ TypeScript ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ์—์„œ ์ฝ”๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ”ฎ ๊ฒฐ๋ก 

TypeScript๋Š” ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ง€์›๋˜๋ฏ€๋กœ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋งค์ผ TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ๋งŽ์€ ์˜ˆ์ œ์™€ ์„ค๋ช…์„ ํฌํ•จํ•ด TypeScript์˜ ๊ฐ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋งŽ์€ ์ •๋ณด๊ฐ€ ์žˆ๊ณ , ์ •์  ํƒ€์ดํ•‘์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ๊ฐ€์žฅ ์ ํ•ฉํ•œ ์˜ต์…˜์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค.

 

๋ฐ˜๋ฉด Flow๋Š” React๋กœ Flow๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ผ๋ถ€ ๋ฌธ์„œ์™€ ์งง์€ ๋ฌธ์„œ๋งŒ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๋‹ค๋ฅธ JavaScript ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ Flow๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐ์—๋„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ์ง€๊ธˆ๊นŒ์ง€ PropTypes์€ ์„ธ ๊ฐ€์ง€ ์˜ต์…˜ ์ค‘ ๊ฐ€์žฅ ๋“œ๋ฌธ ๋ฌธ์„œ๋ฅผ ๊ฐ–๊ณ  ์žˆ์ง€๋งŒ ์ด๋Ÿฐ ๊ฒŒ์‹œ๋ฌผ๋„ ๋ช‡ ๊ฐœ ์žˆ๋‹ค.

 

 

 

๐ŸŽง ๋งˆ๋ฌด๋ฆฌ ๋…ธ๋ž˜ ์ถ”์ฒœ..

 

 

์š•์‹ฌ์˜ ๋ฐ˜๋Œ€ํŽธ์œผ๋กœ - ์ตœ์œ ๋ฆฌ

์Œ์•…์ด ํ•„์š”ํ•œ ์ˆœ๊ฐ„, ๋ฉœ๋ก 

www.melon.com

 

 

 

 

 

 

+ Recent posts