본문 바로가기

개발공부/TypeScript

[타입스크립트 입문] 타입스크립트를 왜 써야하는가?

우선 타입스크립트에 대해서 알아보도록 하자.

타입스크립트란?

타입스크립트는 자바스크립트에 '타입(type)'을 부여한 언어이다.
자바스크립트의 확장된 언어라고 볼 수 있다.
타입스크립트는 자바스크립트와 달리 브라우저에서 실행하려면 파일을 한번 변환해주어야 한다.
이 변환 과정을 우리는 컴파일(compile)이라고 부른다.

왜 타입스크립트를 써야하는가?

타입스크립트는 2가지 관점에서 자바스크립트 코드의 품질과 개발 생산성을 높일 수 있다.

  • 에러의 사전 방지
  • 코드 가이드 및 자동 완성(개발 생산성 향상)

각각의 관점에 대해서 하나씩 살펴보도록 하자.

에러의 사전 방지

타입스크립트는 에러를 사전에 미리 예방할 수 있다.

// math.js
function sum(a, b) {
    return a + b;
}
// math.ts
function add(a: number, b:number):number {
    return a + b;
}

두 코드 모두 두 숫자의 합을 구하는 함수 코드이다.
위의 코드는 자바스크립트의 코드이며, 아래의 코드는 타입스크립트의 코드이다.

sum(10, 20)함수를 이용하여 숫자 10과 20을 더하면 우리가 원하는 결과인 30을 얻을 수 있을것이다.
하지만 20을 '20'으로 하여 호출하면 어떤 결과를 얻을까?

위 이미지처럼 30이 아닌 1020이라는 결과가 출력되는 것을 알 수 있다.
하지만 vscode 편집기 상에서는 이렇게 원하는 결과로 나오지 않는다는 사실을 console.log를 통해 출력해봐야지만 알 수 있다.

반면 타입스크립트의 경우 위 이미지와 같이 '20'에 에러줄이 표기되는것을 알 수 있다.
(만약 저처럼 에러 메세지가 보이지 않는 경우 vscode 터미널창에서 확인하시거나 에러줄에 커서를 대보거나, 익스텐션으로 'Error lens'를 설치하시면 저처럼 보이실겁니다.)

이렇게 타입스크립트는 편집기 상에서 원하지 않는 결과에 대해서 사전에 에러를 방지 할 수 있다.

코드 자동 완성과 가이드

타입스크립트의 또 다른 장점은 코드를 작성할 때 개발 툴의 기능을 최대로 활용할 수 있다는 것이다.
VScode는 툴의 내부가 타입스크립트로 작성되어 있어 타입스크립트개발에 최적화 되어있다.
개발자 관점에서 자바스크립트에 타입이 더해졌을때 어떠한 장점이 있는지 코드로 한번 살펴보자.

var total = sum(10, 20)이라는 변수에 담은 후, toLocaleString()메서드를 사용하고자 할때, 위 이미지와 같이 자동완성이 되지 않고
개발자가 오탈자없이 작성해야한다는 번거로운점이 존재한다.
만약 오탈자가 있을 경우, 해당 자바스크립트 파일을 브라우저에서 실행했을 때만 오류를 확인할 수 있었을 것이다.

이번에는 타입스크립트로 작성한 코드를 살펴보자

var result = add(10, 20)과 같이 변수 result에 대한 타입이 지정되어있기 때문에 VScode에서 해당 타입에 대한 API를 미리보기로 띄워줄 수 있기때문에 API를 일일이 타이핑해서 작성하는것이 아니라 tab으로 빠르고 정확하게 작성해나갈 수 있다.
위 이미지에서 보다시피 result.만 해줬을뿐인데 number타입에 해당하는 속성들이 자동적으로 띄워지고 있는것을 확인할 수 있다.

추가로 알아두면 좋은 내용

위 내용에서 에러의 사전방지를 언급하였는데 이 부분에 대해서 좀 더 자세히 알아보도록 하자.
TypeScript는 정적으로 타입이 지정된 JavaScript의 상위집합이며, 주요 장점 중 하나는 컴파일 타임에 오류를 포작하는 기능이다.
이것은 일반 JavaScript에 비해 특정 타입의 오류를 미리 방지하는데 도움이 될 수 있다.
그러나 TypeScript가 여러 가지 이유로 모든 오류를 미리 방지할 수는 없다는 점을 명확히 하는것이 중요하다.

  1. 타입 주석과 타입 추론
  2. 런타임 오류
  3. 타입 단언
  4. 타사 라이브러리
  5. 동적 입력
  6. 불완전한 타입 적용 범위
  7. 과도한 의존

각각에 대해서 살펴보도록 하자

1. 타입 주석과 타입 추론

타입스크립트는 타입 주석을 사용하여 컴파일 타임에 타입 관련 오류를 포착한다.
타입 주석을 제공하지 않거나 타입스크립트가 올바른 타입을 추론할 수 없는 경우 특정 오류를 포착하지 못할 수 있다.
예를 들어 함수 인수나 반환값에 대한 타입을 지정하지 않으면 타입스크립트가 잘못된 매개변수 타입을 감지하지 못할 수 있다.

const result: string = add(1, 2);부분을 타입스크립트는 컴파일 타임에 해당 에러를 잡을것이다.

하지만 아래와 같이 타입이 없으면 오류를 포착하지 못할 수 있다.

왜 잘못된 매개변수 타입을 감지하지 못할까?

타입스크립트는 타입 주석이 제공되지 않거나 여러가지 이유로 올바른 타입을 추론할 수 없는 경우 잘못된 매개변수 타입을 감지하지 못할 수 있다.

  • JavaScript의 동적 입력 : 타입스크립트가 확장하는 언어인 자바스크립트는 동적으로 입력된다.
    이는 변수가 런타임 중에 다양한 타입의 값을 보유할 수 있음을 의미한다.
    타입스크립트의 타입 추론은 코드의 정적 분석을 통해 컴파일 타임에 타입을 결정한다. 정적 분석을 통해 변수 타입을 최종적으로 결정할 수 없는 경우, 타입스크립트는 'any'와 같이 덜 구체적인 타입을 사용할 수 있다.
function add(a, b) {
    return a + b;
}

위 예제코드의 ab의 타입을 살펴보자

위 예제코드에서 타입스크립트는 ab타입이 명시적으로 주석이 지정되지 않았기때문에 추론할 수 없으며 any타입을 할당하도록 대체될 수 있다.

  • 컨텍스트 부족 : 타입스크립트의 타입 추론은 컨텍스트에 민감하다.
    이는 변수나 함수가 해당 타입을 결정하는데 사용되는 컨텍스트에 의존하는 경우가 많다.
    컨텍스트가 모호하거나 불충분하면 타입스크립트가 올바른 타입을 추론하지 못할 수 있다.
function processData(data) {
  // 컨텍스트가 없는 경우 타입스크립트는 'data'의 올바른 유형을 추론하지 못한다.
}

위 예제코드에서 타입스크립트는 함수에 명시적인 타입 주석이 부족하고 'data'에 대해 제공되는 컨텍스트가 없기 때문에 'data'에 어떤 속성이 있어야 하는지 알지 못할 수 있다.

  • Union 타입 : 때로는 변수에 여러개의 유효한 타입이 있을 수 있다.
    타입스크립트는 여러 타입이 가능할 때 Union타입을 추론할 수 있다. 이러한 경우 타입스크립트는 가능한 모든 타입을 고려하기 때문에 특정 오류를 포착하지 못할 수 있다.
    let value = 42; value = 'Hello';
    // 타입스크립트는 'value'의 타입이 number | string 인것을 허용한다.


  • 타입 단언 : 타입스크립트를 사용하면 타입 단언(ex. as 키워드)을 사용하여 타입 검사를 재정의할 수 있다.
    타입 단언을 잘못 사용하거나 타입을 강제 적용하는 경우 타입스크립트가 오류를 포착하지 못할 수 있다.
    let value: number = '42' as number; // 타입스크립트는 해당 단언을 허용한다. 설령 잘못되었을지라도

+ 타사 코드 : 타입 정의가 부족한 타사 라이브러리로 작업하는 경우 타입스크립트에 타입을 올바르게 유추하는데 충분한 정보가 없을 수 있다.
이러한 라이브러리와 인터페이스하려면 사용자 정의 타입 선언을 작성하거나, 'any'타입을 사용해야 할 수도 있다.

정리하자면, 타입 주석 및 추론을 통해 타입 관련 오류를 포착하는 타입스크립트의 기능은 코드의 명확성과 특수성, 변수와 함수가 사용되는 컨텍스트, 타입 주석 및 단언의 정확성에 따라 달라진다.
명시적인 타입 주석을 제공하고 타입 정의에 대한 모범 사례를 딸면 타입스크립트가 컴파일 타임에 더 많은 오류를 포착하는데 도움이 될 수 있다.

2. 런타임 오류

타입스크립트는 주로 타입 불일치, null/undefined 값 및 기타 타입 관련 문제와 관련된 오류를 포착한다.
예상치 못한 데이터나 외부 요인으로 인해 발생하는 로직 오류나 런타임 오류를 잡아내지 못한다.
예를 들어 런타임에 실패하는 네트워크 요청이 있는 경우 타입스크립트는 이를 방지할 수 없다.

fetch('https://example.com/api/data')
    .then(response => response.json())
    .then(data => {
        // API 요청이 실패할 경우 런타임 오류 발생
        console.log(data);
    })
    .catch(error => {
        console.error(error);
    });

타입스크립트는 네트워크 요청 자체의 문제나 API 응답의 오류를 포착할 수 없다.

왜 예상치 못한 데이터나 외부 요인으로 인해 발생하는 로직 오류나 런타임 오류를 잡아내지 못할까?

타입스크립트가 주로 타입 관련 오류를 잡는 데 중점을 두고, 예상치 못한 데이터나 외부 요인으로 인해 발생하는 논리 오류나 런타임 오류를 포착하지 못할 수 있는 이유는 타입스크립트의 주요 목표가 정적 타입 검사를 제공하고 개발자가 개발중에 일반적인 타입 관련 실수를 잡을 수 있도록 돕는것이기 때문이다.
타입스크립트가 이런 방식으로 동작하는 이유는 다음과 같다.

  • 타입 안전성 : 타입스크립트의 주요 목적은 자바스크립트 코드의 타입 안전성을 향상시키는 것이다.
    이는 타입 제약 조건을 적용하고 개발자가 컴파일 타임에 타입 관련 오류를 포착하는데 도움이 된다.
    이렇게 하면 런타임 오류로 이어질 수 있는 많은 일반적인 프로그래밍 실수를 방지할 수 있다.
  • 컴파일 시간과 런타임 비교 : 타입스크립트는 컴파일 시간에 작동한다.
    즉, 코드가 실행되기 전에 코드와 타입 주석을 분석한다.
    가능한 모든 시나리오에 대해 런타임 검사를 수행하도록 설계되지 않았다. 그렇게 하면 상당한 런타임 오버헤드가 발생하기 때문이다.
  • 성능 : 가능한 모든 논리 오류나 예상치못한 데이터에 대해 런타임 검사로 인해 코드 속도가 크게 느려질 수 있다.
    타입스크립트는 타입 안전성과 성능의 균형을 맞추도록 설계되었으며, 컴파일 타임에 효율적으로 포착할 수 있는 타입 관련 문제에 중점을 두어 이를 달성한다.
  • 외부 요인 : 타입스크립트는 네트워크 오류, 하드웨어 문제 또는 기타 런타임 환경 문제와 같은 외부 요인을 예측하거나 제어할 수 없다.
    이는 정적 타입 검사기가 처리할 수 있는 범위를 벗어난다.
  • 복잡성 : 코드 논리 오류는 매우 복잡하고 상황에 따라 달라질 수 있다.
    컴파일 타임에 가능한 모든 논리 오류를 포착하려면 많은 프로그램의 동적이고 예측할 수 없는 특성으로 인해 종종 비실용적이거나 불가능한 수준의 분석이 필요하다.
  • 개발자의 책임 : 타입스크립트는 개발자가 논리 정확성에 대한 책임을 지도록 권장한다.
    타입스크립트가 타입 관련 문제를 해결하는데 도움이 될 수 있지만 개발자에게는 오류 처리, 입력 유효성 검사 및 테스트와 같은 기술을 통해 예상치 못한 시나리오를 잘 처리하는 코드를 작성하는 것이 여전히 중요하다.

정리하자면, 컴파일 타임의 타입 관련 오류에 대한 타입스크립트의 주요 초점은 타입 안정성과 성능의 균형을 맞추는 디자인 선택이다.
이는 논리 오류, 런타임 오류 및 외부 요인을 해결하는데 사용되는 기타 개발 방식 및 도구를 보완하여 소프트웨어 안정성에 대한 보다 포괄적인 접근 방식을 보장한다.

3. 타입 단언

타입스크립트는 타입 검사를 재정의할 수 잇는 타입 단언(ex. as 키워드)을 제공한다.
타입 단언을 잘못 사용하거나 타입을 강제 적용하면 타입스크립트가 포착하지 못하는 런타임 오류를 발생할 수 있다.

const value: any = 'Hello, TypeScript!';
const length: number = value as number; // 타입 단언

// 타입스크립트는 이 타입 단언을 허용하지만 올바르지 않아 런타임 오류가 발생할 수 있다.
console.log(length.toFixed(2)); // Runtime error: length.toFixed is not a function

타입 단언은 타입스크립트의 타입 검사를 우회할 수 있다.
타입 단언을 부적절하게 사용하면 예기치 않은 런타임 동작이 발생할 수 있다.

왜 타입 단언을 잘못 사용하거나 타입을 강제 적용하면 타입스크립트가 포착하지 못하는 런타임 오류를 발생할까?

타입스크립트에서 타입 단언 또는 타입 강제 변환을 잘못 사용하면 타입스크립트가 포착하지 못하는 런타임 오류가 발생할 수 있다.
왜냐하면 타입 단언은 값 타입이 올바르지 않더라도 값 타입에 대한 개발자의 판단을 신뢰하도록 타입스크립트에 효과적으로 지시하기 때문이다.
이로 인해 런차임 오류가 발생할 수 있는 이유는 다음과 같다.

  • 타입 단언 타입 검사 우회 : as 키워드 또는 꺽쇠 괄호(<>)와 함께 타입 단언을 사용하면 타입스크립트에 자신보다 타입을 더 잘 알고 있다고 알리는 것이다. 값을 지정된 타입이 있는것처럼 처리한다.
    타입스크립트는 컴파일 타임에 타입 검사나 유효성 검사를 수행하지 않고 이를 허용한다.
let value: any = '42';
let numberValue: number = value as number; // 타입 단언

위 예에서 타입스크립트는 'value'가 문자열인 경우에도 타입 단언을 허용한다.
단언이 올바른지 확인하지 않는다. 왜냐하면 이것은 개발자의 의도를 신뢰하기 때문이다.

  • 잘못된 변환 가능성 : 타입 단언은 런타임 오류를 일으킬 수 있는 잘못된 타입 변환으로 이어질 수 있다.
    실제로 갖고있지 않은 타입을 갖는 값을 주장하는 경우, 런타임 시 예상치 못한 동작이나 예외가 발생할 수 있다.
let value: any = 'Hello'; 
let numberValue: number = value as number; // 올바르지 않은 타입 단언
// 런타임 시 'Hello'를 숫자로 변환할 수 없기 때문에 런타임 오류(NaN)가 발생한다.

타입스크립트는 단언이 유효하다고 가정하고 그렇지 않은 경우 런타임 시 코드가 실패한다.
 + 타입 안전성 부족 : 타입 단언은 타입 관련 오류를 방지하기 위해 존재하는 타입스크립트의 타입 안전성 검사를 우회한다.
타입 단언을 부주의하거나 부정확하게 사용하면 타입스크립트가 제공하는 타입 안전성의 이점을 잃게 된다.
 + 유지관리 문제 : 타입 단언이 자주 발생하거나 잘못된 코드가 포함된 코드는 유지관리가 어려워질 수 있다.
특정 타입 단언이 사용된 이유가 다른 개발자(또는 미래의 자신)에게 명확하지 않을 수 있다. 이로 인해 혼란이 발생하고 오류 위험이 높아질 수 있다.

타입 스크립트에서는 타입 단언을 아껴서 신중하게 사용하는 것이 중요하다.
다음은 몇가지 모범사례이다.

  • 유형에 대해 확신이 있고 타입스크립트의 타입 검사를 우회할 충분한 이유가 있는 경우에만 타입 단언을 사용하여야 한다.
  • 더 나은 타입 안전성으로 타입 변환을 수행하는 내장 자바스크립트 메소드(parseInt, parseFloat, Number() 등)와 같은 타입 변환을 위한 다른 메커니즘을 선호한다.
  • 불확실한 타입을 처리할 때는 타입 가드 또는 type-safe functions을 사용하는것을 고려하세요.

이러한 모범 사례를 따르면 잘못된 타입 단언이나 타입 강제 변환으로 인해 발생하는 런타임 오류 위험을 최소화하는 동시에 타입스크립트의 정적 타입 검사의 이점을 누릴 수 있다.

4. 타사 라이브러리

타입스크립트는 코드 또는 타입 정의를 사용할 수 있는 코드에서만 오류를 포착할 수 있다.
타입 정의없이 타사 라이브러리를 사용하는 경우 타입스크립트가 방지할 수 없는 런타임 오류가 발생할 수 있다.

import ThirdPartyLibrary from 'third-party-library';
const result: string = ThirdPartyLibrary.someFunction(); // 이 라이브러리에 대해 타입을 확인할 수 없다.

타사 라이브러리에 타입 정의가 없으면 타입스크립트는 타입 검사를 제공할 수 없다.
타입스크립트는 타입 정의 없이 외부 코드에 대해 타입 안전성을 보장할 수 없다.

왜 타입스크립트는 코드 또는 타입 정의를 사용할 수 있는 코드에서만 오류를 포착할 수 있을까?

타입스크립트는 컴파일 프로세스 중에 정적 타입 검사를 수행하기 위해 타입 정보에 의존하기 때문에 주로 코드 또는 타입 정의가 가능한 코드에서 오류를 포착할 수 있다.
이러한 제한이 존재하는 이유는 다음과 같다.

  • 정적 타입 검사 : 타입스크립트는 정적으로 타입이 지정된 언어이다. 즉, 코드를 분석하고 컴파일 타임에 타입 관련 오류를 확인한다.
    이는 코드에 제공된 타입 주석과 타입 정보를 검사하여 수행된다.
  • 타입 정의 : 타입 정의(일반적으로 .d.ts 파일에 있음)는 타입스크립트의 외부 자바스크립트 라이브러리 또는 모듈 간의 브리지 역할을 한다.
    이러한 정의는 해당 라이브러리에 있는 코드의 유형, 구조 및 인터페이스에 대한 필수 정보를 타입스크립트에 제공한다.
    타입 정의가 없으면 타입스크립트에는 타입 확인에 필요한 정보가 부족해진다.
  • 타입 추론 : 타입스크립트는 명시적인 타입 주석 없이도 어느 정도 타입을 유추할 수 있다. 그러나 이 추론은 타입스크립트가 코드와 사용가능한 타입 정의에서 결정할 수 있는것으로 제한된다.
    타입 추론이 불가능하거나 타입 정의가 누락된 경우 타입스크립트는 호환성을 유지하기 위해 'any'와 같은 덜 구체적인 타입을 사용할 수 있다.
  • 타입 안전성 : 타입스크립트의 목표는 코드가 실행되기 전에 타입 관련 오류를 포착하여 더 안전하고 유지 관리하기 쉬운 코드를 작성하도록 돕는 것이다.
    사용 가능한 타입 정보를 기반으로 타입 검사를 시행함으로써 타입스크립트는 코드가 예상 타입을 준수하는지 확인하여 런타임 타입 관련 오류 가능성을 줄인다.
  • 외부 라이브러리 : 타입스크립트로 작성되지 않고 타입 정의를 제공하지 않는 외부 라이브러리나 모듈을 사용하는 경우 타입스크립트는 추가 정보 없이 이러한 외부 종속성 타입을 분석할 수 없다.
    여기서는 사용자가 이를 올바르게 사용하는 방법을 알고 있으며 해당 라이브러리와의 상호작용에 대한 컴파일 타임 타입 검사를 제공할 수 없다고 가정한다.

정리하자면, 오류를 포착하는 타입스크립트의 능력은 타입정보의 가용성과 정확성에 달려있다.
이는 코드와 적절한 타입 주석 또는 타입 정의가 있는 코드에서 오류를 효과적으로 포착할 수 있다.
타입 정의가 없는 외부라이브러리나 코드로 작업할 때 타입 안전성을 유지하고 런타임 오류를 방지하기 위해 각별히 주의해야하며 잠재적으로 타입 단언이나 기타 기술을 사용해야 할 수도 있다.

왜 타입 정의없이 타사 라이브러리를 사용하는 경우 타입 스크립트가 방지할 수 없는 런타임 오류가 발생할까?

타입스크립트에서 유형 정의없이 타사 라이브러리를 사용하면 다음과 같은 여러 이유로 인해 타입스크립트가 방지할 수 없는 런타임 오류가 발생할 수 있다.

  • 타입 불일치 : 타입스크립트는 타입 정보를 사용하여 컴파일 타임에 타입 관련 오류를 포착한다.
    타입 정의없이 타사 라이브러리를 사용하는 경우 타입스크립트는 코드와 라이브러리 간의 상호 작용에 대해 타입검사를 수행할 수 없다.
    이러한 타입 정보 부족으로 인해 런타임 시 타입 불일치 및 오류가 발생할 수 있다.
// 타입 정의 없이 타사 라이브러리를 사용
import ThirdPartyLibrary from 'third-party-library';

const result: string = ThirdPartyLibrary.someFunction(); // 'someFunction'에 대한 타입검사를 할 수 없다.

위 예제코드에서 someFunction이 문자열을 반환할 것으로 예상되지만 런타임에 숫자를 반환하는 경우 타입스크립트는 타사 라이브러리에 대한 타입 정보가 부족하기 때문에 이 오류를 포착하지 않는다.

  • 부정확한 타입 주석 : 타입 정의 없이 타사 라이브러리를 사용하는 경우 'any'타입을 사용하거나 부적절한 타입 주석을 사용하여 타입스크립트 오류를 억제할 수 있다. 하지만 이로 인해 부정확한 타입 정보가 발생하고 잠재적으로 런타임 오류가 발생할 수 있다.
// Using 'any' type to suppress TypeScript errors
import ThirdPartyLibrary from 'third-party-library';

const result: any = ThirdPartyLibrary.someFunction(); // No type checking, 'result' is of type 'any'

여기서 타입스크립트를 사용하면 result에 어떤 타입이든 할당할 수 있지만 이로 인해 타입스크립트가 방지할 수 없는 런타임 타입 문제가 발생할 수 있다.

 + 제한된 IntelliSense 및 문서화 : 타입스크립트이 자동 완성 및 문서화 기능(IntelliSense)은 사용 가능한 타입 정의가 있을 때 가장 잘 작동한다.
타입 정의가 없으면 IntelliSense 제안을 얻지 못할 수 있으므로 라이브러리를 올바르게 사용하기가 어려워 진다.
 + No Compile-Time Safety : 타입 스크립트는 타입 정의 없이 타사 라이브러리와 상호 작용하는 코드에 대해 컴파일 시간 안전 보장을 할 수 없다.(No Compile-Time Safety) 즉, 라이브러리 문제는 런타임에만 표면화될 수 있으므로 예기치 않은 동작 및 런타임 오류가 발생할 위험이 높아진다.

타입 정의없이 타사 라이브러리를 사용할 때 이러한 문제를 완화하려면 다음 내용들을 수행하자.

  • 사용자 정의 타입 정의 생성 : 타사 라이브러리에 대한 고유한 유형 정의(.d.ts 파일)을 작성하거나 특정 소스 또는 다른 소스의 커뮤니티 제공 타입 정의를 사용하는 것을 고려하자. 이를 통해 타입스크립트는 라이브러리 사용법에 대한 타입 검사를 수행할 수 있다.
  • 타입 단언 사용시 주의 : 타입 정의없이 라이브러리를 사용할 수 밖에 없는 경우 타입 단언(ex. as 키워드)을 사용하여 타입스크립트에 타입에 대해 알릴 수 있다. 그러나 런타임 오류의 위험을 최소화하려면 주의를 기울여 단언이 올바른지 확인해야한다.
  • 타사 라이브러리 래핑 : 타입이 안전한 추상화 및 인터페이스를 제공하는 타사 라이브러리 주변에 래퍼 또는 어댑터를 만든다.
    이런 방식으로 라이브러리의 동작을 캡슐화하고 래퍼 코드에 타입 검사를 추가할 수 있다.

정리하자면, 오류를 포착하는 타입스크립트의 능력은 종종 타입 정의에 의해 제공되는 정확한 타입 정보를 갖는데 달려 있다.
타입 정의 없이 타사 라이브러리를 사용하는 경우 타입스크립트는 타입 안전성을 보장할 수 없으므로 잠재적인 런타임 오류를 방지하기 위해 추가 예방 조치를 위하는 것이 중요하다.

5. 동적 입력

타입스크립트는 정적으로 입력되지만 자바스크립트 자체는 동적으로 입력된다.
타입스크립트는 자바스크립트의 동적 타이핑과 관련된 위험을 완전히 제거할 수 없다.
예를 들어 타입 강제 변환이나 예상치 못한 런타임 유형 변경과 관련된 문제가 여전히 발생할 수 있다.

let x: number = 5;  
x = 'Hello'; // 타입스크립트가 이 타입 불일치를 탐지하지 않는다.

타입스크립트는 자바스크립트의 동적 타이핑과 관련된 문제를 방지할 수 없다.
즉, 타입스크립트는 런타임 시 타입 변경을 예측하거나 방지할 수 없다.

왜 타입스크립트는 자바스크립트의 동적 타이핑과 관련된 위험을 완전히 제거할 수 없을까?

타입스크립트는 자바스크립트에 정적 타이핑 계층을 추가하지만 다음과 같은 여러가지 이유로 자바스크립트의 동적 타이핑과 관련된 위험을 완전히 제거할 수는 없다.

  • 자바스크립트 호환성 : 타입스크립트는 자바스크립트의 엄격한 상위 집합으로 설계되었다. 즉, 기존 자바스크립트 코드와 호환되어야 한다.
    이러한 호환성은 타입스크립트가 자바스크립트의 기본 측면인 동적 타입 지정 및 타입 강제 변환을 허용한다는것을 의미한다.
    타입스크립트는 자바스크립트와의 호환성을 유지하면서 이러한 측면을 제거할 수 없다.
  • 자바스크립트의 동적 특성 : 자바스크립트는 본질적으로 동적으로 타입이 지정되는 언어로, 변수는 런타임 중에 타입을 변경할 수 있다.
    타입스크립트는 주로 컴파일 타임에 정적 타이핑을 제공하지만 자바스크립트의 런타임 동작을 변경하지는 않는다.
    이것은 타입스크립트 코드를 작성할 때에도 런타임에 동적 타입 관련 문제가 계속 발생할 수 있음을 의미한다.
  • 타입 단언 : 타입스크립트는 개발자가 의도적으로 타입검사를 재정의할 수 있도록 하는 타입단언과 같은 도구를 제공한다.
    타입단언을 오용하거나 부주의하게 사용하면 타입스크립트가 포착하지 못하는 유형 관련 문제가 발생할 수 있다.

    다음은 타입 단언을 잘못 사용한 예시 코드이다.
let x: number = 5;
x = 'Hello'; // TypeScript would catch this type mismatch, but...

let y: any = 5;
y = 'Hello' as number; // ...this type assertion bypasses TypeScript's checks and can lead to runtime errors.
  • 외부 라이브러리 : 타입스크립트의 타입 검사는 사용 가능한 타입 정보만큼 강력하다.
    외부 자바스크립트 라이브러리나 타입 정의가 없는 코드로 작업할 때 타입스크립트는 애플리케이션의 해당 부분에서 타입 관련 문제를 방지할 수 없다.
    타입 안전성을 제공하기 위해 타입 주석 및 정의에 의존한다.
  • 타입 강제 변환 : 자바스크립트는 특정 작업에서 타입 강제 변환(암시적 타입 변환)을 수행하며 이로 인해 예기치 않은 결과가 발생할 수 있다.
    타입스크립트는 이러한 동작이 자바스크립트 언어 디자인의 핵심이기 때문에 제거할 수 없다.
    const result: string = 5 + '5';
    // TypeScript allows this, but it may not be the desired result
  • 런타임 타입 변경 : 자바스크립트를 사용하면 객체가 런타임 중에 동적으로 구조나 유형을 변경할 수 있다.
    타입스크립트의 정적 타입 검사는 이러한 변경을 예상하거나 방지할 수 없다.
    본질적으로 타입스크립트는 정적 타입 검사와 컴파일 타임에 타입 관련 오류를 포착하기 위해 더 나은 도구를 제공하여 자바스크립트를 보완한다.
    그러나 자바스크립트의 동적 특성과 타입 강제 변환은 언어의 일부이며 이러한 기능과 관련된 위험을 완전히 제거할 수는 없다는 점을 인정한다.
    개발자는 자바스크립트의 동적 입력과 관련된 위험을 완화하기 위해 여전히 주의를 기울이고, 강력한 코드를 작성하고, 테스트 및 코드 검토와 같은 추가 관행을 고려해야한다.
    let obj: { prop: number } = { prop: 5 }; obj.prop = 'Hello';
    // TypeScript doesn't catch this type change at runtime

6. 불완전한 타입 적용 범위

복잡한 시나리오에 대한 포괄적인 타입 주석을 작성하는 것은 어려울 수 있다.
어떤 경우에는 완벽한 타입 적용 범위가 아닐수도 있고 타입스크립트가 모든 잠재적 오류를 포착하지 못할 수도 있다.

const data: { name: string; age: number } = { name: 'Alice' };  
console.log(data.age.toFixed(2)); // Runtime error: data.age is undefined

복잡한 시나리오에는 완벽한 타입 적용 범위가 없을 수 있다.
완전한 타입 정보를 제공하지 않으면 타입스크립트가 모든 오류를 포착하지 못할 수 있다.

어떤 경우에서 완벽한 타입 적용 범위가 아닐수도 있고 타입스크립트가 모든 잠재적 오류를 포착하지 못하는걸까?

그 이유들은 다음과 같다.

  • 복잡한 데이터 구조 : 깊게 중첩된 객체, 혼합 타입의 배열 또는 복잡한 데이터 흐름과 같은 복잡한 데이터 구조가 있는 애플리케이션에서는 다양한 데이터 요소간의 구조 및 관계를 정확하게 반영하는 타입 주석을 생성하기 어려울 수 있다.
  • 동적 데이터 : 타입스크립트의 정적 타입 시스템은 동적으로 변경되거나 외부 요인의 영향을 받는 데이터를 처리하는데 적합하지 않는다.
    예를 들어 API에서 가져온 데이터는 다양한 구조를 가질 수 있으며 이러한 데이터에 대한 정확한 타입을 정의하는것이 어려울 수 있다.
  • 외부 종속성 : 포괄적인 타입 정의가 부족한 타사 라이브러리 또는 API로 작업할 때 타입스크립트에는 정확한 타입 검사를 제공하는 데 필요한 정보가 없을 수 있다. 이로인해 "any" 타입이 발생하거나 타입 적용이 불완전해질 수 있다.
  • 타입 추론 제한 사항 : 타입스크립트의 타입 추론은 강력하지만 제한 사항이 있다.
    경우에 따라 타입스크립트가 타입을 정확하게 추론하지 못할 수도 있다. 특히 복잡하거나 동적으로 생성된 데이터를 처리할 때 더욱 그렇다.
  • 일반 코드 : 일반 함수와 클래스는 유연성을 제공하지만 정확하게 입력하기 어려울 수 있다. 제네릭 형식은 복잡성을 야기하는 경우가 많으며 모든 시나리오에서 타입 안전성을 보장하기 어려울 수 있다.
  • 타입 단언 : 부정확하거나 지나치게 허용적인 타입 단언은 타입스크립트의 타입 검사를 우회하고 타입 관련 오류를 일으킬 수 있다.

이러한 것들을 해결하기 위한 몇가지 전략은 다음과 같다.

  • 점진적 타입 지정 : 타입스크립트를 사용하면 코드베이스에 타입을 점진적으로 추가할 수 있다.
    한번에 모든 내용에 주석을 달 필요가 없다.
    코드베이스의 가장 중요한 부분부터 시작하여 가장 중요한 value에 타입 주석을 점진적으로 추가하자.
  • "undefined" 및 "any" 타입을 드물게 사용 : 타입스크립트는 유연성에 의해 "undefined" 및 "any" 타입을 제공하지만 이러한 타입은 드물게 사용하는 것이 가장 좋다.
    이러한 타입을 과도하게 사용하면 타입스크립트의 오류 포착 기능이 약화될 수 있다.
  • 타입 가드 및 단언 : 타입 가드를 구현하고 타입 단언을 신중하게 사용하여 타입스크립트의 추론이 부족하거나 타입을 정확하게 정의할 수 없는 시나리오에서 타입 안전성을 보장한다.
  • 문서화 : 타입 주석이 완벽하지 않은 경우 예상되는 데이터 구조 및 타입을 설명하는 문서로 코드를 보완하는것을 고려하자.
    이것은 다른 개발자가 의도된 사용법을 이해하는데 도움이 될 수 있다.
  • 테스팅 : 유닛(unit) 테스트, 통합(intefration) 테스트, 엔드 투 엔드(end-to-end) 테스트를 활용하여 타입스크립트가 놓칠 수 있는 오류를 잡아낸다.
    테스트를 통해 코드의 정확성에 대한 추가적인 신뢰도를 얻을 수 있다.
  • 코드 리뷰 : 철저한 코드리뷰를 수행하여 타입 관련 문제를 파악하고 타입 주석이 코드 동작을 정확하게 반영하는지 확인한다.

타입스크립트는 코드 품질을 향상시키고 버그를 줄이는 도구이지만 신중한 설계 및 세부사항에 대한 주의의 필요성을 대체하지는 못한다.
완벽한 타입 적용을 달성하는 것은 어려울 수 있지만 타입스크립트를 효과적으로 사용하면 코드 유지 관리성과 견고성을 크게 향상시킬 수 있다.

7. 과도한 의존

오류 방지를 위해 타입스크립트에만 의존하면 보안에 대한 잘못된 인식을 갖게 될 수 있다.
정적 타입 검사를 테스트, 코드 검토, 사용자 입력의 철저한 검증 등 다른 개발 방식과 결합하는 것이 중요하다.

function divide(a: number, b: number): number {  
return a / b;  
}

// 타입스크립트는 0으로 나눌수있지만 이것은 논리 오류이다.  
const result: number = divide(10, 0); // No TypeScript error

추가 확인 없이 타입스크립트에 과도하게 의존하면 문제가 발생할 수 있다.
타입스크립트는 타입 제약 조건을 적용하지만 0으로 나누기와 같은 논리 오류를 포착하지 않는다.
이러한 예는 타입스크립트의 한계와 이를 다른 개발 방식 및 도구와 결합하여 강력하고 안정적인 코드를 보장하는 것의 중요성을 보여준다.

정리하자면 타입스크립트는 컴파일 타임에 특정 타입의 오류를 포착하고 코드 품질을 향상시키는 강력한 도구이지만 모든 오류, 특히 런타임 문제, 외부요인 또는 타입스크립트 기능의 오용과 관련된 오류를 사전에 예방할 수는 없다.
개발자는 애플리케이션의 안정성을 보장하기 위해 여전히 주의를 기울이고 다른 전략을 고려해야한다.


타입스크립트를 잘 사용하기 위해서는 자바스크립트의 기본이 잘되어있어야한다는 것을 또 한번 깨달았다..

참고자료 : 타입스크립트 입문 - 기초부터 실전까지