๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

โœ๏ธ/React

React ๊ณต๋ถ€ํ•˜๊ธฐ(8) - ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์—์„œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์‚ฌ์šฉํ•˜๊ธฐ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

1. IDE(Integrated Development Environment)๋ฅผ ๋”์šฑ ๋” ์ ๊ทน์ ์œผ๋กœ ํ™œ์šฉ (์ž๋™์™„์„ฑ, ํƒ€์ž…ํ™•์ธ)

2. ์‹ค์ˆ˜ ๋ฐฉ์ง€

 

 

1. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์—ฐ์Šต

 

$ mkdir ts-practice # ts-practice ๋ผ๋Š” ๋””๋ ‰ํ„ฐ๋ฆฌ ์ƒ์„ฑ
$ cd ts-practice # ํ•ด๋‹น ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™
$ yarn init -y # ๋˜๋Š” npm init -y

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ts-practice ๋””๋ ‰ํ„ฐ๋ฆฌ์— package.json ์ด๋ผ๋Š” ํŒŒ์ผ์ด ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

 

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์„ค์ •ํŒŒ์ผ ์ƒ์„ฑํ•˜๊ธฐ

$ yarn global add typescript

๊ทธ๋ฆฌ๊ณ  ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ ์•ˆ์—์„œ tsc --init ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด tsconfig.json ํŒŒ์ผ์ด ์ž๋™์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

<tsconfig.json>

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist"
  }
}

 

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ

<src/practice.ts>

const message: string = 'hello world';
console.log(message);

์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ์ž‘์„ฑํ•˜์…จ์œผ๋ฉด ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์˜ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์œ„์น˜ํ•œ ํ„ฐ๋ฏธ๋„์—์„œ tsc ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ด๋ณด์„ธ์š”.

๊ทธ๋Ÿฌ๋ฉด dist/practice.js ๊ฒฝ๋กœ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํŒŒ์ผ์ด ์ƒ์„ฑ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

tsc // ์ปดํŒŒ์ผ

node dist/practice // ์‹คํ–‰

<dist/practice.js>

"use strict";
var message = 'hello world';
console.log(message);

 

๊ธฐ๋ณธ ํƒ€์ž…

<src/practice.ts>

let count = 0; // ์ˆซ์ž
count += 1;
count = '๊ฐ‘์ž๊ธฐ ๋ถ„์œ„๊ธฐ ๋ฌธ์ž์—ด'; // ์ด๋Ÿฌ๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค!

const message: string = 'hello world'; // ๋ฌธ์ž์—ด

const done: boolean = true; // ๋ถˆ๋ฆฌ์–ธ ๊ฐ’

const numbers: number[] = [1, 2, 3]; // ์ˆซ์ž ๋ฐฐ์—ด
const messages: string[] = ['hello', 'world']; // ๋ฌธ์ž์—ด ๋ฐฐ์—ด

messages.push(1); // ์ˆซ์ž ๋„ฃ์œผ๋ ค๊ณ  ํ•˜๋ฉด.. ์•ˆ๋œ๋‹ค!

let mightBeUndefined: string | undefined = undefined; // string ์ผ์ˆ˜๋„ ์žˆ๊ณ  undefined ์ผ์ˆ˜๋„ ์žˆ์Œ
let nullableNumber: number | null = null; // number ์ผ์ˆ˜๋„ ์žˆ๊ณ  null ์ผ์ˆ˜๋„ ์žˆ์Œ

let color: 'red' | 'orange' | 'yellow' = 'red'; // red, orange, yellow ์ค‘ ํ•˜๋‚˜์ž„
color = 'yellow';
color = 'green'; // ์—๋Ÿฌ ๋ฐœ์ƒ!

 

ํ•จ์ˆ˜์—์„œ ํƒ€์ž… ์ •์˜ํ•˜๊ธฐ

<src/practice.ts>

function sum(x: number, y: number): number {
  return x + y;
}
sum(1, 2);

function sumArray(numbers: number[]): number {
  return numbers.reduce((acc, current) => acc + current, 0);
}
const total = sumArray([1, 2, 3, 4, 5]);

// ๋ฐ˜ํ™˜X
function returnNothing(): void {
  console.log('I am just saying hello world');
}

 

interface ์‚ฌ์šฉํ•ด๋ณด๊ธฐ (for ํด๋ž˜์Šค ๋˜๋Š” ๊ฐ์ฒด๋ฅผ ์œ„ํ•œ ํƒ€์ž… ์ง€์ •)

 

ํด๋ž˜์Šค์—์„œ interface๋ฅผ implementsํ•˜๊ธฐ

<practice.ts>

// Shape ๋ผ๋Š” interface ๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.
interface Shape {
  getArea(): number; // Shape interface ์—๋Š” getArea ๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ๊ผญ ์žˆ์–ด์•ผ ํ•˜๋ฉฐ ํ•ด๋‹น ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์€ ์ˆซ์ž์ž…๋‹ˆ๋‹ค.
}

class Circle implements Shape {
  // `implements` ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ Shape interface ์˜ ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.

  radius: number; // ๋ฉค๋ฒ„ ๋ณ€์ˆ˜ radius ๊ฐ’์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  constructor(radius: number) {
    this.radius = radius;
  }

  // ๋„ˆ๋น„๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  getArea() {
    return this.radius * this.radius * Math.PI;
  }
}

class Rectangle implements Shape {
  width: number;
  height: number;
  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }
  getArea() {
    return this.width * this.height;
  }
}

const shapes: Shape[] = [new Circle(5), new Rectangle(10, 5)];

shapes.forEach(shape => {
  console.log(shape.getArea());
});
// Shape ๋ผ๋Š” interface ๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.
interface Shape {
  getArea(): number; // Shape interface ์—๋Š” getArea ๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ๊ผญ ์žˆ์–ด์•ผ ํ•˜๋ฉฐ ํ•ด๋‹น ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์€ ์ˆซ์ž์ž…๋‹ˆ๋‹ค.
}

class Circle implements Shape {
  // `implements` ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ Shape interface ์˜ ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜๊ฒ ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
  constructor(public radius: number) {
    this.radius = radius;
  }

  // ๋„ˆ๋น„๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  getArea() {
    return this.radius * this.radius * Math.PI;
  }
}

class Rectangle implements Shape {
  constructor(private width: number, private height: number) {
    this.width = width;
    this.height = height;
  }
  getArea() {
    return this.width * this.height;
  }
}

const circle = new Circle(5);
const rectangle = new Rectangle(10, 5);

console.log(circle.radius);
console.log(rectangle.width);

const shapes: Shape[] = [new Circle(5), new Rectangle(10, 5)];

shapes.forEach(shape => {
  console.log(shape.getArea());
});

tsc // ์ปดํŒŒ์ผ

node dist/practice // ์‹คํ–‰

public์œผ๋กœ ์„ ์–ธ๋œ ๊ฐ’: ํด๋ž˜์Šค ์™ธ๋ถ€์—์„œ ์กฐํšŒ ๊ฐ€๋Šฅ

private์œผ๋กœ ์„ ์–ธ๋œ ๊ฐ’: ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ๋งŒ ์กฐํšŒ ๊ฐ€๋Šฅ

 

์ผ๋ฐ˜ ๊ฐ์ฒด๋ฅผ interface๋กœ ํƒ€์ž… ์„ค์ •ํ•˜๊ธฐ

<practice.ts>

interface Person {
  name: string;
  age?: number; // ๋ฌผ์Œํ‘œ๊ฐ€ ๋“ค์–ด๊ฐ”๋‹ค๋Š” ๊ฒƒ์€, ์„ค์ •์„ ํ•ด๋„ ๋˜๊ณ  ์•ˆํ•ด๋„ ๋˜๋Š” ๊ฐ’์ด๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
}
interface Developer {
  name: string;
  age?: number;
  skills: string[];
}

const person: Person = {
  name: '๊น€์‚ฌ๋žŒ',
  age: 20
};

const expert: Developer = {
  name: '๊น€๊ฐœ๋ฐœ',
  skills: ['javascript', 'react']
};
interface Person {
  name: string;
  age?: number; // ๋ฌผ์Œํ‘œ๊ฐ€ ๋“ค์–ด๊ฐ”๋‹ค๋Š” ๊ฒƒ์€, ์„ค์ •์„ ํ•ด๋„ ๋˜๊ณ  ์•ˆํ•ด๋„ ๋˜๋Š” ๊ฐ’์ด๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
}
interface Developer extends Person {
  skills: string[];
}

const person: Person = {
  name: '๊น€์‚ฌ๋žŒ',
  age: 20
};

const expert: Developer = {
  name: '๊น€๊ฐœ๋ฐœ',
  skills: ['javascript', 'react']
};

const people: Person[] = [person, expert];

 

Type Alias ์‚ฌ์šฉํ•˜๊ธฐ

type: ํŠน์ • ํƒ€์ž…์— ๋ณ„์นญ์„ ๋ถ™์ด๋Š” ์šฉ๋„๋กœ ์‚ฌ์šฉ => ๊ฐ์ฒด๋ฅผ ์œ„ํ•œ ํƒ€์ž…์„ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ๊ณ , ๋ฐฐ์—ด ๋˜๋Š” ๊ทธ ์–ด๋–ค ํƒ€์ž…์ด๋˜ ๋ณ„์นญ์„ ์ง€์–ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

<src/practice.ts>

type Person = {
  name: string;
  age?: number; // ๋ฌผ์Œํ‘œ๊ฐ€ ๋“ค์–ด๊ฐ”๋‹ค๋Š” ๊ฒƒ์€, ์„ค์ •์„ ํ•ด๋„ ๋˜๊ณ  ์•ˆํ•ด๋„ ๋˜๋Š” ๊ฐ’์ด๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
};

// & ๋Š” Intersection ์œผ๋กœ์„œ ๋‘๊ฐœ ์ด์ƒ์˜ ํƒ€์ž…๋“ค์„ ํ•ฉ์ณ์ค๋‹ˆ๋‹ค.
// ์ฐธ๊ณ : https://www.typescriptlang.org/docs/handbook/advanced-types.html#intersection-types
type Developer = Person & {
  skills: string[];
};

const person: Person = {
  name: '๊น€์‚ฌ๋žŒ'
};

const expert: Developer = {
  name: '๊น€๊ฐœ๋ฐœ',
  skills: ['javascript', 'react']
};

type People = Person[]; // Person[] ๋ฅผ ์ด์ œ ์•ž์œผ๋กœ People ์ด๋ผ๋Š” ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
const people: People = [person, expert];

type Color = 'red' | 'orange' | 'yellow';
const color: Color = 'red';
const colors: Color[] = ['red', 'orange'];

 

Generics => ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ํƒ€์ž…์— ๋Œ€ํ•˜์—ฌ ํ˜ธํ™˜์„ ๋งž์ถฐ์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉ

 

ํ•จ์ˆ˜์—์„œ Generics ์‚ฌ์šฉํ•˜๊ธฐ

<src/practice.ts>

function merge<A, B>(a: A, b: B): A & B {
  return {
    ...a,
    ...b
  };
}

const merged = merge({ foo: 1 }, { bar: 1 });
function wrap<T>(param: T) {
  return {
    param
  }
}

const wrapped = wrap(10);

 

interface์—์„œ Generics ์‚ฌ์šฉํ•˜๊ธฐ

<src/practice.ts>

interface Items<T> {
  list: T[];
}

const items: Items<string> = {
  list: ['a', 'b', 'c']
};

 

type์—์„œ Generics ์‚ฌ์šฉํ•˜๊ธฐ

<src/practice.ts>

type Items<T> = {
  list: T[];
};

const items: Items<string> = {
  list: ['a', 'b', 'c']
};

 

ํด๋ž˜์Šค์—์„œ Generics ์‚ฌ์šฉํ•˜๊ธฐ

class Queue<T> {
  list: T[] = [];
  get length() {
    return this.list.length;
  }
  enqueue(item: T) {
    this.list.push(item);
  }
  dequeue() {
    return this.list.shift();
  }
}

const queue = new Queue<number>();
queue.enqueue(0);
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
queue.enqueue(4);
console.log(queue.dequeue());
console.log(queue.dequeue());
console.log(queue.dequeue());
console.log(queue.dequeue());
console.log(queue.dequeue());
$ tsc
$ node dist/practice

0
1
2
3
4

 

 

2. ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ์ž‘์„ฑํ•˜๊ธฐ

 

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

$ npx create-react-app ts-react-tutorial --template typescript

 

์ƒˆ๋กœ์šด ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

<src/Greetings.tsx>

import React from 'react';

type GreetingsProps = {
  name: string;
  mark: string;
  optional?: string;
  onClick: (name: string) => void; // ์•„๋ฌด๊ฒƒ๋„ ๋ฆฌํ„ดํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ํ•จ์ˆ˜๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
};

function Greetings({ name, mark, optional, onClick }: GreetingsProps) {
  const handleClick = () => onClick(name);
  return (
    <div>
      Hello, {name} {mark}
      {optional && <p>{optional}</p>}
      <div>
        <button onClick={handleClick}>Click Me</button>
      </div>
    </div>
  );
}

Greetings.defaultProps = {
  mark: '!'
};

export default Greetings;

<App.tsx>

import React from 'react';
import Greetings from './Greetings';

const App: React.FC = () => {
  const onClick = (name: string) => {
    console.log(`${name} says hello`);
  };
  return <Greetings name="Hello" onClick={onClick} />;
};

export default App;