ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JSX의 불편함을 해결한다는 TSRX, 직접 따져봤습니다
    개발 이야기 2026. 6. 22. 11:22

    최근 FrontOverflow 매거진에서 TSRX라는 기술을 접했습니다. Inferno를 만들고 React, Svelte 팀을 거친 Dominic Gannaway가 개발한 TypeScript 언어 확장인데요, 간단히 말하면 "JSX의 불편한 부분을 언어 레벨에서 고쳐보겠다"는 시도입니다. 현재 알파 단계라 실무 투입과는 거리가 있지만, 설계 방향 자체가 흥미로워서 찬찬히 뜯어봤습니다.


    TSRX가 뭘 고치려는 건가요

    JSX를 쓰다 보면 반복적으로 걸리는 부분들이 있습니다. TSRX는 그중 네 가지를 언어 차원에서 건드립니다.

    1. Hook은 왜 조건문 앞에 있어야 할까요

    React를 배우면서 누구나 한 번쯤 부딪히는 규칙입니다. "Hook은 최상위에서만 호출해야 한다"는 제약 때문에, early return을 먼저 쓰고 싶어도 Hook을 그 위에 올려야 합니다. 결과적으로 코드 흐름이 뒤집힙니다.

    // JSX: 손님이 왔을 때 규정상 전체 재고 파악부터 해야 하는 편의점처럼
    function UserProfile({ userId }) {
      const user = useUser(userId);       // Hook이 조건 전에
      const [tab, setTab] = useState("info");
    
      if (!userId) return <p>로그인이 필요합니다.</p>;
      // ...
    }
    

    TSRX에서는 컴파일러가 Hook을 자동으로 최상단에 끌어올려 주기 때문에, 논리 흐름대로 조건을 먼저 확인하고 나중에 Hook을 쓸 수 있습니다.

    component UserProfile({ userId }) {
      if (!userId) {            // 조건 먼저
        <p>"로그인이 필요합니다."</p>
        return;
      }
      const user = useUser(userId);  // 그다음 Hook
      // ...
    }
    

    2. prop 하나 추가했을 뿐인데 왜 네 군데를 수정해야 할까요

    기존 컴포넌트에 enabled 같은 조건 prop을 하나 추가하면, JSX에서는 조건 생성 로직, optional chaining, 의존성 배열, 반환 조건 렌더링을 각각 찾아서 수정해야 합니다. 코드가 흩어져 있으니 하나라도 빠뜨리면 버그가 납니다.

    TSRX에서는 기존 코드를 if (enabled) { } 블록 안에 넣고 들여쓰기만 하면 끝입니다. 내부 로직은 건드리지 않아도 됩니다.

    3. .map() 안에서 계산 좀 하려면 왜 이렇게 복잡해질까요

    .map() 콜백 안에서 파생 값을 계산하면 return과 key, 중괄호 중첩이 겹치면서 코드가 금방 복잡해집니다. TSRX는 for...of 문법으로 루프를 작성하기 때문에, 중간에 변수를 선언하고 조건 분기를 하는 게 훨씬 자연스럽습니다.

    4. 스타일이 왜 꼭 다른 파일에 있어야 할까요

    TSRX는 <style> 블록을 컴포넌트 안에 선언할 수 있습니다. 컴파일하면 스코프가 자동으로 처리된 CSS 클래스로 변환되기 때문에, CSS Modules처럼 파일을 분리하고 import한 뒤 styles.xxx로 참조하는 과정이 없어집니다.


    이 설계의 핵심은 무엇인가요

    JSX 요소를 표현식이 아닌 문(statement)으로 다룬다는 점입니다. 덕분에 if, for, 변수 선언이 마크업과 같은 층위에서 섞입니다. 로직 흐름과 UI가 자연스럽게 이어지는 구조입니다.

    Vue SFC나 Svelte도 "한 파일에 다 모으기" 철학은 같지만, 그쪽은 <template>, <script>, <style> 섹션이 나뉩니다. TSRX는 섹션 구분 자체가 없습니다.


    그래서 실제로는 어떨까요

    솔직하게 정리하면 이렇습니다.

    트레이드오프가 존재합니다. 파일 수가 줄어드는 대신 파일당 코드 줄이 길어집니다. 총 복잡도는 그대로고, 분산 방식만 바뀌는 겁니다.

    JSX   →  파일 많음 + 파일당 줄 짧음
    TSRX  →  파일 적음 + 파일당 줄 길음
    

    어느 쪽이 낫냐는 팀이 어떤 방식으로 코드를 탐색하느냐에 달려 있습니다. 파일 간 이동이 불편한 팀에게는 TSRX가 편하고, 긴 파일을 스크롤하는 게 불편한 팀에게는 JSX 분리가 낫습니다.

    중규모 이상에서는 고려할 게 너무 많습니다. 팀원마다 "이 파일 이제 쪼갤 때 됐다"는 기준이 다르고, 기존 디자인 시스템과 충돌 가능성도 있습니다. 알파 단계라 lint, 포맷터, CI 도구 체인도 직접 구성해야 하며, 신규 입사자 온보딩에 TSRX 문법 학습 비용이 추가됩니다. 잘 맞지 않으면 다시 JSX로 돌아가는 마이그레이션 비용도 감수해야 합니다.

    그렇다고 언어 설계 자체의 개선이 소규모 전용인 건 아닙니다. Hook hoisting이나 루프 스코핑 같은 언어 레벨 개선은 오히려 규모가 클수록 이점이 두드러집니다. 다만 지금 당장 쓰지 못하는 이유가 기술 자체가 아니라 알파라는 성숙도 문제라는 게 정확한 표현입니다.


    가장 본질적인 문제

    프론트엔드 기초를 다진다는 관점에서 보면 TSRX의 접근이 오히려 역효과를 낼 수 있습니다.

    TSRX가 추상화하는 것들을 한번 살펴보면 이렇습니다.

    • Hook이 최상위에서만 호출되는 이유 → React 렌더링 모델 이해
    • .map()에 key가 필요한 이유 → DOM 재조정(reconciliation) 이해
    • CSS 스코프가 필요한 이유 → 캐스케이딩 이해

    이것들은 제약이 아니라 배워야 할 개념들입니다. 컴파일러가 이를 숨겨버리면 제약이 사라지는 게 아니라 배울 기회가 사라집니다. 나중에 문제가 생겼을 때 TSRX 코드에서 컴파일된 React 코드로, 다시 런타임 동작으로 역추적해야 하는데, 기초가 없으면 이 과정에서 완전히 길을 잃게 됩니다.

    결국 TSRX를 제대로 쓰려면 추상화하려는 것들을 먼저 깊이 알고 있어야 합니다. 그 정도 실력이면 JSX의 제약이 크게 불편하지도 않습니다. 숙련자한테는 굳이 필요 없고, 초중급자한테는 오히려 해롭습니다.


    정리하며

    TSRX는 흥미로운 언어 설계 실험입니다. Hook 규칙이나 루프 스코핑 같은 언어 레벨 개선은 분명히 가치가 있고, 아이디어 자체는 유효합니다. 다만 지금 시점에서는 알파 단계의 성숙도 문제, 제한된 생태계, 그리고 "파일 구조의 복잡도를 줄이는 게 아니라 재배치하는 것"이라는 본질적 한계가 실익을 좁힙니다.

    가장 솔직한 평가는 이렇습니다. 실익이 있는 구간이 매우 좁습니다. TSRX가 추상화하는 것들을 이미 깊이 이해하고 있는 숙련자이면서, 그럼에도 JSX의 제약이 여전히 거슬리는 사람. 그런 분이 소규모 프로젝트에서 빠르게 개발할 때가 가장 잘 맞는 상황입니다.

    Dominic Gannaway가 과거에 만든 것들, Inferno 그리고 React와 Svelte에 기여한 컴파일 타임 최적화들이 결국 생태계에 흡수됐던 것처럼, TSRX의 아이디어들도 언젠가 주류 프레임워크에 영향을 줄 가능성은 충분히 있습니다. 개인적인 생각으로는 지금 당장 쓰기보다는 지켜볼 기술로 보고 있습니다.

Designed by Tistory.