본문 바로가기

HTML ⁄ CSS ⁄ JS

타입스크립트 기초

 

왜 타입스크립트를 쓰는가?

타입스크립트의는 JavaScript 프로그램을 위한 정적 Type Checker 역할을 목표로 한다.

개발자가 코드를 작성하며 만드는 오류 중, 가장 일반적인 것은 Type Error라고 할 수 있다. 단순 오타부터 시작해서, 라이브러리의 API 인터페이스를 제대로 이해하지 못했거나, 런타임에 어떻게 동작할지 잘못 예측하는 등의 경우 모두 포함된다.

타입스크립트를 사용하면 런타임 이전에 작성된 Type이 올바른지 확인하고, 코드 상에서 예기치 않은 동작을 발견한다면 이를 개발자에게 알려주어 버그를 줄일 수 있게된다.

 

 

기초 문법

Interface 사용하기

Interface를 선언함으로써 객체의 구조를 정의할 수 있다.

interface User {
  name: string;
  id: number;
}
 
const user: User = {
  name: "haru",
  username: "haru",
    // Type '{ username: string; id: number; }' is not assignable to type 'User'.
    // Object literal may only specify known properties, 
    // and 'username' does not exist in type 'User'.
  id: 365,
};

Interface를 리턴값이나 매개변수를 나타내는데에도 사용할 수 있다.

function getAdminUser(): User {
  //...
}
 
function deleteUser(user: User) {
  // ...
}

 

Interface에는 JavaScript의 기본 타입(boolean, bigint, null, number, string, symbol 및 undefined)을 기본적으로 사용할 수 있다. 그 외에 사용가능한 타입들은 any, unknown, never, void 등이 있다.

 

Type 사용하기

타입스크립트에서는 union, generic 등의 방법으로 복합적으로 Type을 구성할 수 있다.

Union은 다음과 같이 같은 boolean 끼리, string 끼리, number 끼리 중 가능한 값들을 묶어서 사용할 수 있다.

type isClicked = true | false;

type buttonShape = "default" | "pill" | "round" | "square";
type buttonSize = "xs" | "sm" | "md" | "lg" | "xl";
type PositiveOddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;

혹은 아예 다른 타입끼리도 묶어서 사용할 수 있다.

function wrapInArray(obj: string | string[]) {
  if (typeof obj === "string") {
    return [obj];
            
(parameter) obj: string
  }
  return obj;
}

Generic은 변수에 타입을 지정할 수 있게 해준다. 일반 자바스크립트 Array에는 아무 타입의 값이나 넣을 수 있는 반면, 아래와 같이 generic으로 타입을 지정하면 지정한 타입에 맞는 원소만 가질 수 있게 된다.

type StringArray = Array<string>;
type NumberArray = Array<number>;
type ObjectWithNameArray = Array<{ name: string }>;

아래 예시에서 backpack.get의 경우 string을 반환하게 되어있어 경고가 표시된다.

interface Backpack<Type> {
  add: (obj: Type) => void;
  get: () => Type;
}
 
// This line is a shortcut to tell TypeScript there is a
// constant called `backpack`, and to not worry about where it came from.
declare const backpack: Backpack<string>;
 
// object is a string, because we declared it above as the variable part of Backpack.
const object = backpack.get();
 
// Since the backpack variable is a string, you can't pass a number to the add function.
backpack.add(23);
Argument of type 'number' is not assignable to parameter of type 'string'.

 

TypeScript 마이그레이션

노드 패키지 매니저로 typescript를 전역으로 설치해준다. 

npm i -D typescript ts-loader @types/react @types/react-dom @types/react-router-dom @types/jest @typescript-eslint/eslint-plugin @typescript-eslint/parser
npx tsc --init

init을 하면 tsconfig.json 파일이 생긴다. 필요한 설정만 켜준다.

/* Visit https://aka.ms/tsconfig.json to read more about this file */
{
  "compilerOptions": {
    /* Language and Environment */

    "target": "es5" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
    "jsx": "react-jsx" /* Specify what JSX code is generated. */,
    "jsxImportSource": "@emotion/react" /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */,

    /* Modules */

    "module": "esnext" /* Specify what module code is generated. */,
    "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,

    /* JavaScript Support */
    "allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */,

    /* Emit */
    "outDir": "./dist/" /* Specify an output folder for all emitted files. */,

    /* Interop Constraints */
    "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
    "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,

    /* Type Checking */
    "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied `any` type.. */,
    "noImplicitThis": true /* Enable error reporting when `this` is given the type `any`. */,
    "strictNullChecks": true /* When type checking, take into account `null` and `undefined`. */,
    "strictFunctionTypes": true /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */,
    "strictPropertyInitialization": true /* Check for class properties that are declared but not set in the constructor. */,
    "alwaysStrict": true /* Ensure 'use strict' is always emitted. */,

    /* Completeness */
    "skipLibCheck": true /* Skip type checking all .d.ts files. */
  },
  "include": ["src/**/*"]
}

웹팩에서 entry를 index.tsx 로 바꿔주고 타입스크립트를 자바스크립트로 바꿔주는 ts-loader 도 설정만 추가해준다.

const getConfig = ({ isDev, isAnalyzeMode }) => ({
  mode: isDev ? 'development' : 'production',

  resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'] },
  entry: {
    main: './src/index.tsx',
  },
  ...
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        use: {
          loader: 'ts-loader',
          options: {
            configFile: path.resolve(__dirname, 'tsconfig.json'),
            transpileOnly: true,
          },
        },
        exclude: /node_modules/,
      },
  ...

테스트 차원에서 greeter.ts 를 생성하고, 터미널에서 터미널에서 tsc greeter.ts 를 실행하면 타입스크립트 컴파일러가 ts 파일을 js 파일로 컴파일 해준다. 그런데 어차피 에디터에서 바로 에러가 뜨기 때문에 tsc 명령어로 컴파일러를 실행할 일은 많지 않아 보인다.

// greeter.ts
interface Person {
  firstName: string;
  lastName: string;
}
 
function greeter(person: Person) {
  return "Hello, " + person.firstName + " " + person.lastName;
}
 
let user = { firstName: "Jane", lastName: "User" };
 
document.body.textContent = greeter(user);

 

 

추천영상

 

 

참고자료