CH2 타입시스템_러닝타입스크립트

영훈·2024년 7월 8일
0

_러닝TS

목록 보기
1/1

자바스크립트의 힘은 유연함에서 나옵니다. 그 유연함을 조심하세요!

2장에서 타입 검사기가 실제로 어떻게 작동하는지 알아보자.

2.1 타입의 종류

타입은 자바스크립트에서 다루는 값의 형태에 대한 설명이다.

형태란? 값에 존재하는 속성과 메서드 그리고 내장되어 있는 typeof 연산자가 설명하는 것을 의미한다.

예시 코드

let singer = "Aretha";

예를 들어 다음과 같이 초깃값이 ‘Aretha`인 변수를 생성할 경우, 타입스크립트는 singer 변수가 문자열 타입임을 유추할 수 있다.

타입스크립트의 가장 기본적인 타입은 JS의 일곱가지 기본 원시 타입(primitive type) 동일합니다.

타입스크립트는 다음 원시타입을 다음과 같이 분류한다.

  • null → null;
  • undefined → undefined;
  • boolean → true;
  • string → “Louise”;
  • number → “1337”;
  • bigint → “1337n”;
  • symbol → Symbol(”Franklin”);

타입스크립트는 계산된 초깃값을 갖는 변수의 타입을 유추할 수 있을 만큼 똑똑하다.
(JS 삼항연산자를 가지고 해당 삼항연산자 변수의 타입을 string으로 유추하는 정보상자에 대한 예시를 책에서 제시했다.)

자바스크립트에서 객체와 원시 타입 간의 차이점을 떠올려보세요. Boolean과 Number와 같은 객체는 각 원싯값을 감싸는 객체입니다. 타입스크립트에서는 일반적으로 boolean과 number처럼 소문자로 참조하는 것이 모범 사례입니다.

2.1.1 타입 시스템

타입 시스템(type system)은 프로그래밍 언어가 프로그램에서 가질 수 있는 타입을 이해하는 방법에 대한 규칙 집합이다.

기본적으로 타입스크립트의 타입 시스템은 다음과 같이 작동한다.

  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. firstName의 .length 멤버를 함수처럼 호출하는 코드를 확인합니다.
  4. string의 .length 멤버는 함수가 아닌 숫자라는 오류를 표시합니다. 즉, 함수처럼 호출 할 수 없습니다.

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

2.1.2 오류 종류

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

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

둘 사이의 차이점은 중요하다. 자세히 알아보자.

구문 오류

구문 오류는 타입스크립트가 코드로 이해할 수 없는 잘못된 구문을 감지할 때 발생.

이는 타입 스크립트가 타입스크립트 파일에서 자바스크립트 파일을 올바르게 생성할 수 없도록 차단한다.

물론 TS 코드를 JS 코드로 변환하는데 사용하는 도구와 설정에 따라 JS 코드를 얻을 수 있다. 하지만 결과가 우리의 예상과 상당히 다를수도 있다.

다음 타입스크립트에서는 예기치 않은 let 에 대한 구문 오류가 발생합니다.

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

타입스크립트 컴파일러 버전에 따라 컴파일된 자바스크립트 결과는 다음과 같다.

let let, wat;

타입스크립트는 구문 오류와는 상관없이 자바스크립트 코드를 출력하기 위해 최선을 다하지만, 여러분이 원하는 출력 결과가 아닐 수 있습니다. 따라서 출력된 자바스크립트를 실행하기 전에 구문 오류를 수정하는 것이 좋습니다.

타입 오류

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

타입스크립트는 타입 오류가 있음에도 불구하고 JS 코드를 출력할 수 있지만, 출력된 JS 코드가 원하는 대로 실행되지 않을 가능성이 있다는 신호를 타입 오류로 알려줍니다. 자바스크립트를 실행하기 전에 타입 오류를 확인하고 발견된 문제를 먼저 해결하는 것이 가장 좋습니다.

어떤 프로젝트는 구문 오류 뿐 아니라 모든 타입스크립트 타입 오류가 수정될 때까지 코드 실행을 차단하기도 합니다. 필자를 포함한 많은 개발자는 이 방식이 성가시고 불필요하다고 생각합니다. 대부분의 프로젝트는 13장에서 살펴볼 구성 옵션과 tsconfig.json 파일을 사용해 차단하지 않도록 설정합니다.

2.2 할당 가능성

타입스크립트는 변수의 초깃값을 읽고 해당 변수가 허용되는 타입을 결정합니다. 나중에 해당 변수에 새로운 값이 할당되면, 새롭게 할당된 값의 타입이 변수의 타입과 동일한지 확인합니다.

타입스크립트 변수에 동일한 타입의 다른 값이 할당될 때는 문제가 없습니다.

예를 들어 변수가 처음에 string 값이면 나중에 다른 string 값을 할당하는 것은 문제가 되지 않습니다.

let firstName = "Carole";
firstName = "Joan";

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

예를 들어 처음에는 string 값으로 변수를 선언한 다음 나중에 boolean 값을 넣을 수 없습니다.

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

타입스크립트에서 함수 호출이나 변수에 값을 제공할 수 있을지 여부를 확인하는 것을 할당가능성(assignability)라고 합니다.

즉, 전달된 값이 예상된 타입으로 할당 가능한지 여부를 확인합니다.

할당가능성은 이번장 이후 더 복잡한 객체를 비교할 때 더 중요한 용어가 됩니다.

2.2.1 할당 가능성 오류 이해하기

Type ... is not assignable to type .. 형태의 오류는 타입스크립트 코드를 작성할 때 만나게 되는 가장 일반적 오류 중 하나이다.

해당 오류 메시지에서 언급된 첫번째 type은 코드에서 변수에 할당하려고 시도하는 값이다. 두번째 type 은 첫번째 타입, 즉, 값이 할당되는 변수이다.

예를 들어, 이전 코드 스니펫에서 lastName = true를 작성할 때 boolean 타입인 true 값을 string 타입인 변수 lastName에 할당하려고 했다.

책을 읽으면서 점점 복잡한 할당 가능성 문제를 보게 될 것입니다. 그리고 실제 타입과 예상된 타입 간에 보고된 차이점을 이해하려면 주의 깊게 읽어야 합니다. → 실제 타입과 예상된 타입 간에 차이점을 이해.

2.3 타입 애너테이션

때로는 변수에 타입스크립트가 읽어야 할 초깃값이 없는 경우도 있다. 타입스크립트는 나중에 사용할 변수의 초기 타입을 파악하려고 시도하지 않는다.
그리고 기본적으로 변수를 암묵적인 any 타입으로 간주한다. 변수는 세상 모든 것이 될 수 있음을 나타낸다.

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

예시 코드

let rocker; // type: any
rocker = "Joan Jett" // type: str

rocker.toUpperCase(); // OK

rocker = 19.58; // type : number
rocker.toPrecision(1); // OK

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

예시 코드를 보면 진화하는 any 변수 rocker 에 처음에는 문자열이 할당되는데, toUpperCase() 같은 str 메서드를 갖는 것을 의미하지만, 다음엔 number 타입으로 진화되는 것을 확인할 수 있다.
TS 는 number 타입으로 진화한 변수가 toUpperCase() 메서드를 호출하는 것을 포착했다. 그러나 변수가 str 타입에서 num 타입으로 진화된것이 처음부터 의도된 것인지 알수없습니다.

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

타입 스크립트는 초깃값을 할당하지 않고 변수 타입을 선언할 수 있는 구문인 타입 어노테이션(type annotation)을 제공합니다. 타입 어노테이션은 변수 이름 뒤에 배치되며 콜론(:)과 타입 이름을 차례로 기재합니다. 이런 식으로요

예시 코드

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

이러한 타입 어노테이션은 타입스크립트에만 존재하며 런타임 코드에 영향을 주지도 않고, 유효한 JS 구문도 아닙니다. tsc 명령어를 실행해 TS 소스 코드를 JS로 컴파일하면 해당 코드가 삭제됩니다. 예를 들어 앞의 예제는 다음 JS 코드로 컴파일됩니다.

// 출력된 .js 파일
let rocker;
rocker = "Joan Jett";

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

2.3.1 불필요한 타입 어노테이션

타입 어노테이션은 타입 스크립트가 자체적으로 수집할 수 없는 정보를 타입스크립트에 제공할 수 있습니다. 타입을 즉시 유추할 수 있는 변수에도 타입 어노테이션을 사용할 수 있습니다. 하지만 TS가 아직 알지 못하는 것은 알려주지 못합니다.

다음 코드에서 str 타입 어노테이션은 중복입니다. 타입스크립트가 이미 firstName 이 str 타입임을 유추할 수 있기 때문입니다.

예시코드

let firstName: string = "Tina"; // 타입 시스템은 변경되지 않음.

초깃값이 있는 변수에 타입 어노테이션을 추가하면 타입스크립트는 변수에 할당된 값의 타입이 일치하는지 확인합니다.

다음 firstName은 string 타입으로 선언되었지만, number 값인 42로 초기화되었습니다.

예시코드

let firstName: string = 42;
//  ~~~~~~~~~
// Error: Type 'number' is not assignable to type 'string'.

보통 아무것도 변하지 않는 변수에는 타입 어노테이션을 추가하지 않기를 선호합니다 .타입 어노테이션은 수동으로 작성하는 일은 번거롭습니다. 특히 타입이 변경되거나 복잡한 타입일 때 더욱 그렇습니다.

코드를 명확하게 문서화하거나 실수로 변수 타입이 변경되지 않도록 타입스크립트를 보호하기 위해 변수에 명시적으로 타입 어노테이션을 포함하는 것이 경우에 따라서는 유용할 수 있습니다.

2.4 타입 형태

타입스크립트는 벼눗에 할당된 값이 원래 타입과 일치하는지 확인하는 것 이상을 수행합니다.

타입스크립트는 객체에 어떤 멤버 속성이 존재하는지 알고 있습니다.

코드 예시

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

str 타입의 rapper 변수를 선언한다고 가정합니다. 나중에 rapper 변수를 사용할 때 TS가 str 타입에서 사용 가능한 작업만을 허용한다.

TS 가 str 타입에서 작동하는지 알 수 없는 작업은 허용되지 않는다.

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

타입은 더 복잡한 형태, 특히 객체일수도 있다. 다음 스니펫에서 타입스크립트는 cher 객체에 middleName 키가 없다는 것을 알고 오류를 표시합니다.

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

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

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

2.4.1 모듈

JS는 비교적 최근까지 서로 다른 파일에 작성된 코드를 공유하는 방법과 관련도니 사양을 제공하지 않습니다.

ECMA Script 2015 에는 파일간에 가져오고(import) 내보내는(export) 구문을 표준화하기 위해 ECMA Script Modules(ESM)를 추가되었스빈다.

import { value } from './values';

export const doubled = value * 2;

ECMA 스크립트 사양과 일치시키기 위해 명명법을 사용합니다.

  • 모듈. export , import 가 있는 파일
  • 스크립트. 모듈이 아닌 모든 파일

TS 는 최신 모듈 파일을 기존파일과 함께 실행할 수 있습니다.

모듈 파일에 선언된 모든 것은 해당 파일에서 명시한 export 문에서 내보내지 않는 한 모듈 파일에서만 사용할 수 있습니다.

한 모듈에서 다른 파일에 선언된 변수와 동일한 이름으로 선언된 변수는 다른 파일의 변수를 가져오지 않는 한 이름 충돌로 간주하지 않습니다.

(예시생략. 모듈 선언은 전역 스코프로써 변수 선언과 겹치지 않게 간주된다.)

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

profile
Web Frontend Engineer 👷

0개의 댓글