🔥 결론

이론적으로는 전부 .tsx로 써도 동작한다.
실무에서는 명확성 + 타입 안전성 + 빌드 최적화 + 관례 때문에 .ts를 구분한다.


1️⃣ TypeScript 컴파일러 관점

TypeScript

TypeScript는 파일 확장자를 보고 파싱 모드를 결정한다.

.ts

→ JSX 문법을 해석하지 않는 모드

.tsx

→ JSX 문법을 해석하는 모드. 단순히 JSX를 허용하는 게 아니라

TypeScript 컴파일러에게
”이 파일은 UI 레이어다”라고 알려주는 신호다.

즉, 파서(parser)가 다르게 동작한다.


2️⃣ 왜 전부 .tsx로 하면 안 되냐?

기술적으로는 가능하다.
하지만 문제는 모호성(ambiguity) 이다.


⚠️ 예시 1: 제네릭 문법 충돌

const identity = <T>(arg: T) => arg;

이 코드는 .ts에서는 문제 없음.

하지만 .tsx에서는:

<T>

를 JSX 태그로 오해할 수 있다.

그래서 .tsx에서는 종종 이렇게 써야 한다:

const identity = <T,>(arg: T) => arg;

콤마를 넣어야 JSX로 오해하지 않는다.

즉,

.tsx는 제네릭 문법이 더 까다롭다.


3️⃣ 파싱 비용과 빌드 최적화

.tsx는 항상 JSX 가능성을 열어둔다.

  • 파서가 JSX 문법까지 고려

  • AST 구조가 더 복잡

  • 빌드 도구가 JSX 트랜스파일 단계 추가

대규모 프로젝트에서는 이게 성능 차이를 만든다.


4️⃣ 의미적 구분 (가독성)

실무에서 제일 중요한 이유는 이거다.

utils/
  math.ts
components/
  Button.tsx

파일만 봐도 알 수 있다:

  • .ts → 순수 로직

  • .tsx → UI 컴포넌트

이게 협업에서 엄청 중요하다.


5️⃣ React 철학과도 연결됨

React

React는 UI와 로직을 분리하지 않고
컴포넌트 단위로 관리한다.

.tsx는 사실상:

“UI 계층”이라는 의미를 가진다.


6️⃣ 타입 체커 동작 차이

TypeScript 설정에 따라:

{
  "jsx": "react-jsx"
}

이 설정은 .tsx 파일에만 적용된다.

.ts에는 JSX 변환이 적용되지 않는다.


7️⃣ 실무 기준 정리

상황확장자
타입 정의.ts
API 함수.ts
유틸 함수.ts
React 컴포넌트.tsx
JSX 포함.tsx


🧠 한 문장 정리

모든 파일을 .tsx로 할 수는 있지만,
문법 충돌 + 의미 구분 + 성능 + 관례 때문에 .ts를 구분한다.


원하면 다음으로 더 깊게 갈 수 있다:

  • JSX는 정확히 무엇으로 변환되는가?

  • .tsx → JS 컴파일 과정 내부 구조

  • React 17 이후 JSX 자동 변환 원리

  • AST 레벨에서 ts vs tsx 차이

  • 왜 JSX는 JS 문법이 아닌가?

어디까지 파볼까?