기술/TypeScript

[우아한 타입 스크립트 with 리액트] 타입스크립트의 등장, 웹개발의 역사와 자바스크립트의 한계

빔네모 2024. 7. 28. 13:05

1. 웹 개발의 역사

자바스크립트

  • 1990년대 : 마이크로 소프트의 인터넷 익스플로러, 넷스케이프 커뮤니케이션즈의 넷스케이프 내비게이터 를 가장 많이 사용
  • 1995년대 : 넷스케이프의 브랜든 아이크는 웹의 다양한 콘텐츠를 표현하기 위해 플러그인 요소를 쉽게 조합 할 수 있는 새로운 언어가 필요하다고 생각 => 자바스크립트의 탄생
  • 익스플로러의 Jscript vs 넷스케이프의 Javasciprt : 둘다 사용자에게 유의미한 편의성은 제공하지 못함

자바스크립트의 표준, ECMAScript 

  • 경쟁관계이던 익스플로러와 넷스케이프는 자신들의 브라우저 기능을 빠르게 늘리기 시작
  • 추가된 기능은 각자의 브라우저에서만 동작해, 웹페이지가 다르게 동작하거나 제대로 동작하지 않는 크로스 브라우징 이슈 발생
  • 개발자들은 어떤 기능을 추가하기 위해서 두 개의 스크립트를 따로 개발해야 했음

사용자가 새로운 버전이 아닌 구 버전의 브라우저를 사용하거나, 브라우저가 지원하지 않는 코드도 실행시켜 줘야 함.

=> 폴리필(polyfill)과 트랜스파일(transpile) 등장

폴리필 :  브라우저가 지원하지 않는 코드를 브라우저에서 사용할 수 있도록 변환한 코드 조각이나 플러그인.
              ex) core.js, polyfill.io
트랜스파일 : 최신 버전의 코드를 예전 버전의 코드로 변환하는 과정
                ex) Babel

둘 다 최신 기능을 구버전의 실행환경에서 동작할 수 있게 바꿔주는 역할을 한다.
  • 당시 브라우저 호환성 이슈 때문에, 제이쿼리같지 호환성을 고민하지 않고 한 번에 개발할 수 있는 라이브러리가 유행 함
  • 언제까지 라이브러리에 기대어 해결할 수 없이니 근본적인 문제 해결을 위한 표준화 필요성이 제기
       "모든 브라우저에서 동일하게 동작하는 표준화된 자바스크립트가 필요하다"
  • 넷스케이프는 컴퓨터 시스템의 표준을 관리하는 Ecma 인터내셔널(국제표준화기구)에 자바스크립트의 표준화를 위한 자바스크립트 기술 규격을 제출했고, EC-MAScript하는 이름으로 자바스크립트 표준화를 공식화했다.

웹사이트에서 웹 애플리케이션으로의 전환

웹 사이트 : 누구에게나 같은 정보를 보여주며 사용자와 상호작용하지 않음 (정적 사이트, 단방향으로 정보를 제공)

웹 애플리케이션 : 사용자가 직접 정보를 생산하고 공유할 수 있음 (동적 사이트, 쌍방향 소통)

개발 생태계의 발전

대규모 웹 어플리케이션이 등장하면서 개발 생태계도 이런 흐름에 맞춰 변화되었다.

  • 웹페이지를 통으로 개발하는게 아닌, 컴포넌트 단위로 개발 (CBD, 컴포넌트 베이스 개발)
component based development(CBD)
서비스에서 다루는 데이터를 구분하고 그게 맞는 UI를 표현할 수 있게 컴포넌트 단위로 개발하는 접근 방식
재사용할 수 있는 컴포넌트를 개발 또는 조합해서 작은 컴포넌트에서 큰 컴포넌트를 만들어 나간다.
  • Ajax로 전체를 새로고침하지 않아도 자바스크립트의 비동기 요청을 사용해서 페이지의 일부 데이터를 로드
  • PC, Mobile, 테블릿 등 다양한 디스플레이가 등장하며 사용자의 디바이스에 최적화된 UX/UI 필요

개발자 협업의 필요성 증가

한달 전에 만든 함수를 쉽게 파악할 방법은 없을까? 다른 사람이 만든 함수를 쉽게 이해할 수 있을까? 개발에 투입된 인원이 10명이 넘어가면 어떨까? 인원이 많아질 수록 코드를 파악하기 어려워지는 것은 당연 지사다. 결과물이 커졌기 때문에 서비스를 개발하고 나서 유지보수를 하는 데 협업의 중요성도 높아졌다. 대규모 프로덕트를 개발하고 나서 자바스크립트는 유지보수하기 적합한 언어였을까?

2. 자바스크립트의 한계 

동적 타입 언어의 문제

자바스크립트는 동적 타입의 언어다. 

let a = ??
//변수 a의 타입이 number인지 string인지는 실제 코드가 동작할때 a의 1, "1"인지에 따라 결정된다.
let a = 1 //number
let a = "1" //string

변수의 타입을 명시적으로 지정하지 않고 코드가 실행되는 런타임에 변수값이 할당될 때 해당 값의 타입에 따라 변수 타입이 결정된다.

//a,b를 더한 값을 반환하는 함수
const sumNumber = (a, b) => {
  return a + b;
};

sumNumber(1, 2); // 3
//정상적인 동작

sumNumber(1); // NaN
//b에 값을 넣어주지 않아 NaN이 출력되지만 에러를 발생시키지 않음
sumNumber("a", "b"); // "ab"
//a,b가 문자열이기 때문에 문자열로 합쳐져서 출력됨 => 의도와는 다르게 동작하지만 여전히 정상적으로 동작

sumNumber는 두 숫자의 값을 더하기 위해 만들어진 함수지만 인자를 하나를 넣어도, 문자열을 넣어도 오류 없이 정상적으로 동작한다.

즉 개발자의 의도와는 다르게 동작하는건데, 그런데도 자바스크립트는 이 코드를 문제 없이 실행한다. 동적타입의 언어는 상당히 관대하다.

 

자바스크립트의 관대함은 이뿐만이 아니다. 자바스크립트 엔진은 오류를 발생시키는 대신 형변환을 진행한다.

sumNumber(1); // NaN

const sumNumber = (a, b) => {
  //a만 인자를 넣어준 경우, b는 undefined로 인식
  //+undefined는 NaN으로 형변환한 다음 실행을 이어간다.
  return a + b;
};

 한계 극복을 위한 해결 방안

  • JSDoc : 모듈, 클래스, 매서드 등에 대한 API 문서 생성 도구. 주석의 성경을 지니고 있어 강제성을 부여해 사용하긴 어려움
/**
 * 두 숫자를 더합니다.
 * @param {number} a - 첫 번째 숫자
 * @param {number} b - 두 번째 숫자
 * @returns {number} 두 숫자의 합
 */
function add(a, b) {
    return a + b;
}
  • propTypes : 리액트에서 컴포넌트 props 타입을 검사하기 위해 사용, props의 유효한 값이 전달되었는지 확인할 수 있지만 전체 애플리케이션의 타입 검사를 하는데는 사용할 수 없다. 또한 특정 라이브러리에서만 사용할 수 있다는 점에서 한계가 있다.
import React from 'react';
import PropTypes from 'prop-types';

/**
 * 사용자 카드 컴포넌트
 * @param {Object} props - 컴포넌트의 props
 * @param {string} props.name - 사용자 이름
 * @param {number} props.age - 사용자 나이
 * @param {boolean} props.isMember - 회원 여부
 */
function UserCard({ name, age, isMember }) {
    return (
        <div>
            <h1>{name}</h1>
            <p>Age: {age}</p>
            <p>{isMember ? 'Member' : 'Guest'}</p>
        </div>
    );
}

UserCard.propTypes = {
    name: PropTypes.string.isRequired,
    age: PropTypes.number.isRequired,
    isMember: PropTypes.bool
};

export default UserCard;
  • Dart(다트) : 구글이 자바스크립트를 대체하기 위해 사용한 언어로 정적 타입 언어이다. 위의 방법들 보다 근본적인 해결책으로 보였으나 자바스크립트가 자리매김한 상황에서 다트의 등장을 달갑지 않게 보는 시선이 강했다.
void main() {
  String name = 'John';
  int age = 30;
  bool isMember = true;

  print('Name: $name');
  print('Age: $age');
  print('Is Member: $isMember');
}

 

3가지 모두 해결 방안이였으나, 자바스크립트가 스스로 인터페이스를 기술할 수 있는 언어로 발전해야 된다는 목소리가 커졌다.

3. 타입스크립트의 등장

마이크로 소프트는 자바스크립트의 슈퍼셋 언어인 타입스크립트를 공개했다. 다트와 달리 자바스크립트 코드를 그대로 사용할 수 있고 단점은 극복할 수 있었기 때문에 많은 환영을 받았다. 
*슈퍼셋(superset) : 기존 언어에 새로운 기능과 문법을 추가해서 보완하거나 향상하는 것을 말함

안정성 보장

타입스크립트는 정적 타이핑을 제공한다. 컴파일 단계에서 타입 검사를 해주기 때문에 자바스크립트를 사용했을 때 빈번하게 발생하는 타입 에러를 줄일 수 있고, 런타임 에러를 사전에 방지할 수 있어 안정성이 높아졌다.

개발 생산성 향상

VScode 등의 IDE에서 타입 자동완성 기능을 제공한다. 변수와 함수 타입을 추론할 수 있고, 어떤 props를 넘겨야하는지 매번 확인하지 않아도 사용부에서 바로 볼 수 있어서 개발 생산성이 향상된다.

협업에 유리

개발자가 작성한 코드의 의도를 명확하게 전달할 수 있어 유지보수하기 쉬워진다.

타입스크립트의 인터페이스는 복잡한 코드도 쉽게 이해할 수 있게 돕는다. 인터페이스는 객체 구조를 정의하는 역할을 하며, 특정 객체가 가져야 하는 속성과 매서드의 집합을 인터페이스로 정의해서 객체가 그 구조를 따르게 한다.
interface User {
    name: string;
    age: number;
    isMember: boolean;
}

function getUserInfo(user: User): string {
    return `${user.name} is ${user.age} years old. Member status: ${user.isMember}`;
}

자바스크립트에 점진적으로 적용 가능

자바스크립트의 슈퍼셋이기 때문에 일괄 전환이 아닌 점진적 도입이 가능하다.