1. 타입의 종류

타입은 자바스크립트에서 다루는 값의 형태에 대한 설명입니다. 형태란 다음과 같은 내용을 포함합니다.

  • 값에 존재하는 속성
  • 값에 존재하는 메서드
  • 내장되어있는 typeof 연산자가 설명하는 것

예를 들어 다음과 같은 변수를 선언해보겠습니다.

let singer = "Aretha";

타입스크립트는 singer 변수가 문자열 타입임을 유추할 수 있습니다. 타입스크립트의 기본적인 타입은 자바스크립트의 일곱 가지 primitive type과 동일합니다.

  • null
  • undefined
  • number
  • string
  • boolean
  • bigint
  • symbol

타입스크립트는 기본적인 값들을 원시 타입 중 하나로 추론합니다.

  • null; // null
  • undefined; // undefined
  • true; // boolean
  • "Louise" // string
  • 1337; // number
  • 1337n; // bigint
  • Symbol("Franklin"); // symbol

또한 타입스크립트는 초깃값을 갖는 변수의 타입을 유추할 수 있습니다.

// 타입: string
let bestSong = Math.random() > 0.5
    ? "Chain of Fools"
    : "Respect";

타입 시스템

타입 시스템은 프로그래밍 언어가 프로그램에서 가질 수 있는 타입을 이해하는 방법에 대한 규칙 집합입니다. 기본적으로 타입스크립트의 타입 시스템은 다음과 같이 작동합니다.

  1. 코드를 읽고 존재하는 모든 타입과 값을 이해
  2. 각 값이 초기 선언에서 가질 수 있는 타입을 확인
  3. 각 값이 추후 코드에서 어떻게 사용될 수 있는지 모든 방법을 확인
  4. 값의 사용법이 타입과 일치하지 않으면 사용자에게 오류 표시

예시를 살펴보겠습니다.

let firstName = "Whitney";
firstName.length();
// Error: This expression is not callable.
//   Type 'Number' has no call signatures

타입스크립트는 다음과 같은 순서로 오류를 표시합니다.

  1. 코드를 읽고 firstName이라는 변수를 이해
  2. 초깃값이 "Whitney" 이므로 firstName이 string 타입이라고 결론
  3. 변수의 .length 맴버를 함수처럼 호출하는 코드를 확인
  4. 해당 맴버는 함수가 아닌 숫자라는 오류를 표시

타입스크립트의 타입 시스템에 대한 이해는 타입스크립트 코드를 이해하는 데 중요한 기술입니다.

오류 종류

타입스크립트를 작성하는 동안 가장 자주 접하게 되는 오류는 다음과 같습니다.

  • 구문 오류: 타입스크립트가 자바스크립트로 변환되는 것을 차단한 경우
  • 타입 오류: 타입 검사기에 따라 일치하지 않는 것이 감지된 경우

구문 오류

구문 오류는 타입스크립트가 코드로 이해할 수 없는 잘못된 구문을 감지할 때 발생합니다. 이는 타입스크립트가 자바스크립트 파일을 올바르게 생성할 수 없도록 차단합니다. (변환 도구와 설정에 따라 자바스크립트 코드를 얻을 수도 있습니다. tsc 기본 설정에서는 가능합니다.)

let let wat;
// Error: ',' expected.

타입 오류

타입 오류는 타입 검사기가 프로그램의 타입에서 오류를 감지했을 때 발생합니다. 하지만 자바스크립트로 변환되는 것을 차단하지는 않습니다. 그러나 코드가 실행되면 무언가 충돌하거나 예기치 않게 작동할 수 있음을 나타냅니다.

console.blub("Nothing is worth more than laughter.");
// Error: Property 'blub' does not exist on type 'Console'.

타입스크립트는 자바스크립트 코드를 출력할 수 있지만, 출력된 코드가 원하는 대로 실행도지 않을 가능성이 있다는 신호를 타입 오류로 알려줍니다.

프로젝트에 따라 구문 오류뿐만 아니라 모든 타입스크립트 타입 오류가 수정될 때까지 코드 실행을 차단하기도 합니다. 대부분의 프로젝트는 tsconfig.json 파일을 사용해 차단하지 않도록 설정합니다.

2. 할당 가능성

타입스크립트는 변수의 초깃값을 읽고 해당 변수가 허용되는 타입을 결정합니다. 변수에 동일한 타입의 다른 값이 할당될 때는 문제가 없습니다.

let firstName = "carole";
firstName = "joan";

하지만 변수에 다른 타입의 값이 할당되면 타입 오류가 발생합니다.

let lastName = "king";
lastName = true;
// Error: Type 'boolean' is not assignable to type 'string'.

타입스크립트에서 함수 호출이나 변수에 값을 제공할 수 있는지 여부를 확인하는 것을 할당 가능성이라고 합니다. 즉, 전달된 값이 예상된 타입으로 할당 가능한지 여부를 확인합니다.

3. 타입 애너테이션

변수에는 초깃값이 없는 경우도 있습니다. 타입스크립트는 이런 변수를 암묵적인 any 타입으로 간주합니다.

초기 타입을 유추할 수 없는 변수는 진화하는 any라고 부릅니다. 특정 타입을 강제하는 대신 새로운 값이 할당될 때마다 변수 타입에 대한 이해를 발전시킵니다.

let rocker; // 타입: any

rocker = "Joan Jett"; // 타입: string

rocker.toUpperCase(); // Ok

rocker = 19.58; // 타입: number
rocker.toPrecision(1); // Ok

rocker.toUpperCase();
// Error: 'toUpperCase' does not exist on type 'number'.

일반적으로 any 타입을 사용해 진화를 허용하게 되면 타입스크립트의 타입 검사 목적을 부분적으로 쓸모없게 만듭니다. 타입스크립트는 값이 어떤 타입인지 알고 있을때 가장 잘 작동합니다. 따라서 any 타입을 가진 값에는 타입스크립트의 타입 검사 기능을 잘 적용할 수 없습니다.

타입스크립트는 초깃값을 할당하지 않고도 변수의 타입을 선언할 수 있는 타입 애너테이션을 제공합니다. 타입 에너테이션은 변수 이름 뒤에 배치되며 콜론(:)과 타입 이름을 차례대로 기재합니다.

let rocker: string;
rocker = "Joan Jett";

변수에 타입 애너테이션으로 정의한 타입 외에 값을 할당하면 타입 오류가 발생합니다.

let rocker: string;
rocker = 19.58;
// Error: Type 'number' is not assignable to type 'string'.

타입 시스템에만 존재하는 것은 컴파일된 자바스크립트로 복사되지 않습니다. 타입스크립트 타입은 컴파일을 통해 생성된 자바스크립트에 어떠한 영향도 주지 않습니다.

불필요한 타입 애너테이션

타입 애너테이션은 타입스크립트가 자체적으로 수집할 수 없는 정보를 타입스크립트에 제공할 수 있습니다. 그러나 다음 코드에서 string 타입 에너테이션은 중복입니다. 타입 스크립트가 이미 string 타입임을 추론할 수 있기 때문입니다.

let firstName: string = "Tina";

대부분의 개발자는 불필요한 타입 애너테이션을 추가하지 않는 것을 선호합니다. 애너테이션을 수동으로 작성하는 일은 번거로우며 특히 타입이 변경되거나 복잡한 타입일 때 더욱 그렇습니다. 물론 코드를 명확하게 문서화하거나 실수로 변수 타입이 변경되지 않도록 타입스크립트를 보호하기 위해 변수에 명시적으로 애너테이션을 포함하는 것이 경우에 따라서는 유용할 수 있습니다.

4. 타입 형태

타입스크립트는 객체에 어떤 멤버 속성이 존재하는지 알고 있습니다. 만약 코드에서 변수의 속성에 접근하려고 한다면 타입스크립트는 접근하려는 속성이 해당 변수의 타입에 존재하는지 확인합니다.

let rapper = "Queen Latifah";
rapper.length; // Ok

타입스크립트가 string 타입에서 작동하는지 알 수 없는 작업은 허용되지 않습니다.

rapper.push('!');
// Error: Property 'push' does not exist on type 'string'.

타입스크립트는 객체의 형태에 대한 이해를 바탕으로 할당 가능성뿐만 아니라 객체 사용과 관련된 문제도 알려줍니다.

let cher = {
  firstName: "Cherilyn",
  lastName: "Sarkisian",
};

cher.middleName;
// Error: Property 'middleName' does not exist on type
// '{ firstName: string; lastName: string; }'.

모듈

ECMAScript 2015에는 파일 간에 가져오고 내보내는 구문을 표준화하기 위해 ECMAScript Modules(ESM)이 추가되었습니다.

import { value } from "./values";

export const doubled = value * 2;

타입스크립트는 최신 모듈 파일을 기존 파일과 함께 실행할 수 있습니다. 모듈 파일에 선언된 모든 것은 해당 파일에서 명시한 export 문에서 내보내지 않는 한 모듈 파일에서만 사용할 수 있습니다. 즉, 한 모듈에서 다른 파일에 선언된 변수와 동일한 이름으로 선언된 변수는 다른 파일의 변수를 가져오지 않는 한 이름 충돌로 간주하지 않습니다.

그러나 파일이 모듈이 아닌 일반 스크립트인 경우 타입스크립트는 해당 파일을 전역 스코프로 간주하므로 모든 스크립트가 파일의 내용에 접근할 수 있습니다. 즉, 스크립트 파일에 선언된 변수는 다른 스크립트 파일에 선언된 변수와 동일한 이름을 가질 수 없습니다.

// a.ts
const shared = "Cher";
// Error: Cannot redeclare block-scoped variable 'shared'.
// b.ts
const shared = "Cher";
// Error: Cannot redeclare block-scoped variable 'shared'.

해당 오류가 표시되면 파일에 export 또는 import 문을 추가하지 않았기 때문일 수 있습니다. ECMAScript 사양에 따라 export 또는 import 문 없이 파일을 모듈로 만들어야 한다면 파일의 아무 곳에나 export{};를 추가해 강제로 모듈이 되도록 만들 수 있습니다.

const shared = "Cher"; // Ok

export {};

타입스크립트는 CommonJS와 같은 이전 모듈을 사용해 작성된 타입스크립트 파일의 import, export 형태를 인식하지 못하며 일반적으로 require 함수에서 반환된 값을 any 타입으로 인식합니다.

참고

  • 러닝 타입스크립트, OREILLY, 조시 골드버그, 한빛미디어
profile
웹 개발을 공부하고 있는 윤석주입니다.

1개의 댓글

comment-user-thumbnail
2023년 5월 31일

갓봉님 다음 편은 언제 올라오나요?

답글 달기