[TECH-QA] ํƒ€์ž… ์ •์˜ ํŒŒ์ผ(.d.ts)

interface๋‚˜ type์œผ๋กœ ์ •์˜ํ•˜์—ฌ ์“ธ์ˆ˜ ์žˆ๋Š”๋ฐ d.ts๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ  ๋Œ€ํ•˜์—ฌ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ interface๋‚˜ type์„ ์‚ฌ์šฉํ•ด ํƒ€์ž…์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ๋„ .d.ts ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ์‚ฌ์šฉ ๋ชฉ์ ๊ณผ ๋งฅ๋ฝ์˜ ์ฐจ์ด์— ์žˆ์Šต๋‹ˆ๋‹ค. .d.ts ํŒŒ์ผ์€ ์ฃผ๋กœ ์„ ์–ธ ํŒŒ์ผ(Declaration File)๋กœ์„œ ํŠน์ •ํ•œ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ์ผ๋ฐ˜์ ์ธ interface๋‚˜ type ์ •์˜์™€๋Š” ๋‹ค๋ฅธ ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ .d.ts๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ์™€ ๊ทธ ์žฅ์ ์„ ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€์˜ ํ†ตํ•ฉ: ๊ธฐ์กด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋‚˜ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•  ๋•Œ.
  • ์„ ์–ธ๊ณผ ๊ตฌํ˜„ ๋ถ„๋ฆฌ: ํƒ€์ž… ์ •์˜๋ฅผ ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ๋Ÿฐํƒ€์ž„ ์ฝ”๋“œ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์œผ๋ ค ํ•  ๋•Œ.
  • ๊ธ€๋กœ๋ฒŒ ํƒ€์ž… ์ œ๊ณต: ํ”„๋กœ์ ํŠธ ์ „์ฒด์—์„œ ์‚ฌ์šฉํ•  ๊ณตํ†ต ํƒ€์ž…์„ ์ „์—ญ์ ์œผ๋กœ ์„ ์–ธํ•  ๋•Œ.
  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐฐํฌ: ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•ด ํƒ€์ž… ์ •์˜๋ฅผ ์ œ๊ณตํ•  ๋•Œ.
๋ฐ˜๋ฉด, ํ”„๋กœ์ ํŠธ ๋‚ด๋ถ€์—์„œ๋งŒ ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ  ์‚ฌ์šฉํ•  ๋•Œ๋Š” interface๋‚˜ type์„ .ts ํŒŒ์ผ์— ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋” ๊ฐ„๋‹จํ•˜๊ณ  ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. .d.ts๋Š” ํŠนํžˆ ์™ธ๋ถ€์™€์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ๋น›์„ ๋ฐœํ•˜๋Š” ๋„๊ตฌ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜์— ํƒ€์ž… ์ •์˜ ์ถ”๊ฐ€

๊ธฐ์กด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์— ํƒ€์ž…์ด ์—†๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•˜๊ณ , .d.ts ํŒŒ์ผ๋กœ ํƒ€์ž…์„ ์ œ๊ณตํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

๐Ÿ“ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ (math.js)

function add(a, b) {
  return a + b;
}

module.exports = { add };

๐Ÿ“ ํƒ€์ž… ์„ ์–ธ ํŒŒ์ผ (math.d.ts)

export function add(a: number, b: number): number;

๐Ÿ“ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ์‚ฌ์šฉ (app.ts)

import { add } from "./math";

const result = add(5, 3); // result๋Š” number ํƒ€์ž…์œผ๋กœ ์ถ”๋ก ๋จ
console.log(result); // 8

// add("5", "3"); // ์˜ค๋ฅ˜: 'string' ํƒ€์ž…์€ 'number' ํƒ€์ž…์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Œ
math.js๋Š” ํƒ€์ž… ์ •๋ณด๊ฐ€ ์—†๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์ด์ง€๋งŒ, math.d.ts์—์„œ add ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์ •์˜ํ•ด์ค๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ด ์„ ์–ธ ํŒŒ์ผ์„ ์ฐธ์กฐํ•˜์—ฌ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ์ž˜๋ชป๋œ ํƒ€์ž… ์‚ฌ์šฉ ์‹œ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ํƒ€์ž…์ •์˜๋Š” ์ปดํŒŒ์ผ ์‹œ ํƒ€์ž… ์ฒดํฌ์— ์‚ฌ์šฉ๋˜๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋ณ€ํ™˜๋œ ๋Ÿฐํƒ€์ž„ ์ฝ”๋“œ์—๋Š” ํƒ€์ž…์ด ์ง์ ‘ ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ์‹คํ–‰๋˜๋Š” ๋กœ์ง๋งŒ ๋‚จ์Šต๋‹ˆ๋‹ค.

Lodash์™€ ๊ฐ™์€ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ†ตํ•ฉ

Lodash๋Š” ์ธ๊ธฐ ์žˆ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด @types/lodash์™€ ๊ฐ™์€ ํƒ€์ž… ์ •์˜ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๊ฑฐ๋‚˜ ์ง์ ‘ .d.ts ํŒŒ์ผ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ Lodash ์„ค์น˜

npm install lodash
npm install --save-dev @types/lodash //ํƒ€์ž… ์ •์˜ ์„ค์น˜ (DefinitelyTyped ์ œ๊ณต)

๐Ÿ“ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ์‚ฌ์šฉ

import _ from "lodash";

const numbers = [1, 2, 3, 4];
const sum = _.sum(numbers); // sum์€ number ํƒ€์ž…์œผ๋กœ ์ถ”๋ก ๋จ
console.log(sum); // 10

// _.sum("not an array"); // ์˜ค๋ฅ˜: 'string'์€ 'ArrayLike<number>' ํƒ€์ž…์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Œ
@types/lodash ํŒจํ‚ค์ง€๋Š” Lodash์˜ ๋ชจ๋“  ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํƒ€์ž… ์ •์˜๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, _.sum์€ ์ˆซ์ž ๋ฐฐ์—ด์„ ๋ฐ›์•„ ์ˆซ์ž๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋กœ ํƒ€์ž…์ด ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉฐ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

React ์ปดํฌ๋„ŒํŠธ์™€ ํ†ตํ•ฉ

React๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ž‘์„ฑ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ง€๋งŒ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํƒ€์ž… ์ •์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
@types/react์™€ @types/react-dom์„ ํ†ตํ•ด ์ด๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ React ์„ค์น˜

npm install react react-dom
npm install --save-dev @types/react @types/react-dom

๐Ÿ“ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ React ์ปดํฌ๋„ŒํŠธ ์ž‘์„ฑ

import React from "react";
import ReactDOM from "react-dom";

interface Props {
  name: string;
}

const Greeting: React.FC<Props> = ({ name }) => {
  return <h1>Hello, {name}!</h1>;
};

ReactDOM.render(<Greeting name="Alice" />, document.getElementById("root"));

// <Greeting name={123} /> // ์˜ค๋ฅ˜: 'number' ํƒ€์ž…์€ 'string' ํƒ€์ž…์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Œ
@types/react๋Š” React์˜ ํƒ€์ž… ์ •์˜๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, React.FC์™€ ๊ฐ™์€ ํƒ€์ž…์„ ํ†ตํ•ด ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์˜ props ํƒ€์ž…์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. name props๊ฐ€ string์œผ๋กœ ์ •์˜๋˜์—ˆ์œผ๋ฏ€๋กœ, ์ˆซ์ž๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

React์— ์ปค์Šคํ…€ ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ปค์Šคํ…€ .d.ts๋กœ ํ™•์žฅ (์„ ํƒ์ )

๋งŒ์•ฝ React์— ์ปค์Šคํ…€ ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด custom.d.ts ํŒŒ์ผ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ customProp์„ React ์ปดํฌ๋„ŒํŠธ์—์„œ ํƒ€์ž… ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ custom.d.ts

declare module "react" {
  interface CustomComponentProps {
    customProp: boolean;
  }
}

๐Ÿ“ CustomComponent.tsx

import React from "react";

const CustomComponent: React.FC<CustomComponentProps> = ({ customProp }) => {
  return <div>{customProp ? "Yes" : "No"}</div>;
};

export default CustomComponent;

๐Ÿ“ App.tsx

import React from "react";
import CustomComponent from "./CustomComponent";

const App: React.FC = () => {
  return (
      <CustomComponent customProp={true} />
  );
};

export default App;

์ปค์Šคํ…€ .d.ts๋กœ ํ™•์žฅ

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๋Š” ํƒ€์ž…์ด๋‚˜ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๋‚ด์—์„œ ์‚ฌ์šฉํ•  ํƒ€์ž…๋“ค์„ ์ •์˜ ํ• ๋•Œ ์˜ˆ๋กœ svg ํŒŒ์ผ์„ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋„๋ก custom.d.ts ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์ค€๋‹ค.

๐Ÿ“ custom.d.ts

declare module "*.svg" {
  import * as React from "react";

  interface CustomSVGProps {
    title?: string;
  }

  // SVG ์ปดํฌ๋„ŒํŠธ์˜ ์ „์ฒด props ํƒ€์ž… ์ •์˜
  type SVGComponentProps = React.SVGProps<SVGSVGElement> & CustomSVGProps;

  // ReactComponent๋ฅผ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋กœ ์„ ์–ธ
  export const ReactComponent: React.FunctionComponent<SVGComponentProps>;

  // SVG ํŒŒ์ผ์˜ ๊ธฐ๋ณธ ๋‚ด๋ณด๋‚ด๊ธฐ๋กœ ๋ฌธ์ž์—ด URL ์ •์˜
  const path: string;
  export default path;
}
์ด ์„ ์–ธ์„ ์‚ฌ์šฉํ•˜๋ฉด SVG ํŒŒ์ผ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ€์ ธ์™€ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
import { ReactComponent as Icon } from "./icon.svg";
import iconPath from "./icon.svg";

const App: React.FC = () => (
  <div>
    <Icon width="50" height="50" fill="blue" title="My Icon" />
    <img src={iconPath} alt="Icon" width="50" height="50" />
  </div>
);
  • Icon์€ SVGComponentProps ํƒ€์ž…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํƒ€์ž… ๊ฒ€์‚ฌ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋ฉฐ, title์€ ์˜ต์…”๋„๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • iconPath๋Š” string ํƒ€์ž…์œผ๋กœ ์ด๋ฏธ์ง€ ์†Œ์Šค๋กœ ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์ฝ”๋“œ์™€ ํƒ€์ž… ์ •์˜์˜ ๋ถ„๋ฆฌ

ํƒ€์ž… ์ •์˜์™€ ์‹ค์ œ ๊ตฌํ˜„ ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ, .d.ts ํŒŒ์ผ์€ ์„ ์–ธ๋งŒ ํฌํ•จํ•˜๊ณ  ์ด๋Š” ๋Ÿฐํƒ€์ž„์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด .ts ํŒŒ์ผ์— interface๋‚˜ type๊ณผ ํ•จ๊ป˜ ๊ตฌํ˜„ ์ฝ”๋“œ๋ฅผ ์„ž์œผ๋ฉด ์ปดํŒŒ์ผ ์‹œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜๋˜์–ด ๋Ÿฐํƒ€์ž„์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“ .ts ํŒŒ์ผ์— ๋ชจ๋‘ ์ž‘์„ฑ(math.ts)

interface MathOperation {
  (a: number, b: number): number;
}
const add: MathOperation = (a, b) => a + b;
export { add };
math.ts ์ปดํŒŒ์ผ ๊ฒฐ๊ณผ: interface๋Š” ์‚ฌ๋ผ์ง€๊ณ  ๊ตฌํ˜„ ์ฝ”๋“œ๋งŒ ๋‚จ์Œ.

๐Ÿ“ math.d.ts

export interface MathOperation {
  (a: number, b: number): number;
}
export const add: MathOperation;

๐Ÿ“ math.js

const add = (a, b) => a + b;
module.exports = { add };
export const add: MathOperation;
์„ ์–ธ๊ณผ ๊ตฌํ˜„์„ ๋ถ„๋ฆฌํ•˜๋ฉด ์‹ค์ œ ์‹คํ–‰๋˜๋Š” ๋กœ์ง(๊ตฌํ˜„)์€ ๋ณ„๋„์˜ ์†Œ์Šค ํŒŒ์ผ์— ๋‘๊ณ  ํƒ€์ž… ์ •์˜๋Š” ์ฃผ๋กœ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์‚ฌ์šฉ๋˜์–ด ์ฝ”๋“œ์˜ ์ •ํ•ฉ์„ฑ์„ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ํžŒํŠธ๋ฅผ ์ฃผ๋Š” ์—ญํ• ์„ ํ•˜์ง€๋งŒ, ๋Ÿฐํƒ€์ž„์— ์‹คํ–‰๋˜๋Š” ๊ธฐ๊ณ„์–ด ์ฝ”๋“œ๋‚˜ ํ”„๋กœ๊ทธ๋žจ์˜ ๋™์ž‘์—๋Š” ์ง์ ‘์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํƒ€์ž… ์ •์˜๋งŒ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค. ํŠนํžˆ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ†ตํ•ฉํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

interface/type๊ณผ .d.ts์˜ ์ฐจ์ด์  ์š”์•ฝ

ํŠน์ง•
์‚ฌ์šฉ๋ฒ”์œ„
๊ตฌํ˜„ ํฌํ•จ ์—ฌ๋ถ€
๋ชจ๋“ˆ ํ†ตํ•ฉ
์ „์—ญ ์„ ์–ธ
๋ชฉ์ 
interface / typeํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ๋‚ด๋ถ€์—์„œ๋งŒ ์œ ํšจ.ts ํŒŒ์ผ ๋‚ด์—์„œ ๊ตฌํ˜„๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ์™ธ๋ถ€ ๋ชจ๋“ˆ์˜ ํƒ€์ž… ์ˆ˜์ • ๋ถˆ๊ฐ€import/export ํ•„์š”ํ”„๋กœ์ ํŠธ ๋‚ด ํƒ€์ž… ์ •์˜
.d.ts ํŒŒ์ผ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅ์„ ์–ธ๋งŒ ํฌํ•จ, ๊ตฌํ˜„์€ ๋ณ„๋„ ํŒŒ์ผ์—์„œdeclare module๋กœ ์™ธ๋ถ€ ๋ชจ๋“ˆ ํƒ€์ž… ์ •์˜ ๊ฐ€๋Šฅ์ „์—ญ ํƒ€์ž… ์ •์˜ ๊ฐ€๋Šฅ (declare ์‚ฌ์šฉ)์™ธ๋ถ€ ์ฝ”๋“œ์™€์˜ ์ธํ„ฐํŽ˜์ด์Šค ์—ญํ•