[TypeScript] 기본 개념과 실 사용 예시

bien·2026년 2월 10일

리액트

목록 보기
3/3
post-thumbnail

1. TypeScript의 탄생과 역사

JavaScript의 태생적 한계

  • JavaScript는 본래 웹 브라우저의 간단한 상호작용을 위해 만들어진 동적 타입(Dynamic Typing) 언어이다.
    • 변수 설정에 유연함을 가져 소규모 프로젝트에서는 편했으나, 대규모 현업 프로젝트에서는 런타임 에러의 주요 원인이 됨.
  • 이에 Microsift의 앤더스 헤일스버그가 주도하여 TypeScript를 공개함
    • 목표: JavaScript that scales.
      • 즉, 대규모 애플리케이션 도입을 위해 JavaScript에 정적 타입(Static Typing) 시스템을 입힌 것.

2. TypeScript의 주요 특징

  • JavaScript의 상위 집합(Superset)
    • JS의 모든 기능을 포함하면서 그 위에 타입이라는 안전장치를 씌운 것이다.
  • 브라우저는 이해 못 하지만, 개발자를 위해 존재하는 언어이다.
    1. 개발단계에서는 .ts 파일로 엄격한 타입 검사를 받으며 코딩한다.
    2. 빌드 단계(Transpiling)에서는 컴파일러(TSC)나 빌드 도구(Vite 등)가 코드를 순수 JavaScript로 변환한다.
    3. 실행단계: 브라우저는 타입을 모두 떼어내고 로직만 남은 .js를 실행한다.

즉, TypeScript는 JavaScript의 자유분방함에 엄격한 규율과 안정성을 도입하여, 대규모 프론트엔드 프로젝트를 견고하게 만드는 도구

장점

  • 안전성 (Safety): 코드 실헝 전(컴파일 타임)에 오류를 잡아낸다. Uncaught TypeError 같은 악몽을 획기적으로 줄여준다.
  • 생산성 (Tooling): VS Code와 같은 에디터에서 강력한 자동 완성(IntelliSense)과 리팩토링 기능을 제공한다. API의 입출력을 외우지 않아도 점(.)만 찍으면 알 수 있게 해준다.
  • 문서화 (Documentation): 타입 정의 자체가 코드의 문서 역할을 한다. 별도의 주석 없이도 데이터 구조를 파악하기 쉽다.

3. 핵심 문법 (Core Usage)

TypeScript의 본질은 변수와 함수의 모양(Shpae)을 미리 정의하는 것이다.

A. 기본 타입 지정 (Type Annotation)

변수나 함수 파라미터 뒤어 :타입을 붙여 의도를 명확히 한다.

// Java: String name = "Lee";
let name: string = "Lee";
let age: number = 30; // int, float 구분 없이 number

// 함수 파라미터와 반환값 타입 지정
functino add(a: number, b: number): number {
  	return a + b;
}

B. ⭐ 인터페이스(Inteface) - 가장 많이 쓰임

ava의 Class나 DTO와 유사하며, 객체의 구조를 강제하는 데 핵심적으로 사용된다.

interface UserDto {
  id: number;
  username: string; 
  email?: string; // ?는 선택적(Optional) 필드 (null/undefined 가능)
}

const user: UserDto = {
  id: 1,
  username: "DevKim",
  // email은 없어도 에러 안 남
};

C. 제네릭(Generics)

재사용 가능한 컴포넌트나 함수를 만들 때 타입을 유연하게 처리한다.

// T타입의 배열을 받아 T를 반환하는 함수
function getFirstElement<T>(arr: T[]): T {
  return arr[0];
}

const num = getFirstElement<number>([1,2,3]); // num은 number 타입

4. 실무 활용: React 프로젝트에서의 활용

A. 컴포넌트 간 데이터 전달 (Props 정의)

부모 컴포넌트가 자식에게 데이터를 넘겨줄 때, "이 자식은 어떤 데이터를 받아야 하는지" 규격을 정한다. 가장 많이 사용되는 영역.

  • 용도: UI 컴포넌트의 입력값 규격화
  • 효과: 필수값을 빼먹거나(label 누락), 잘못된 타입(onClick에 문자열 전달)을 넣으면 에러가 발생
  • 코드 예시:
// 1. 받는 데이터의 모양(Interface)을 정의
interface ButtonProps {
  label: string;
  onClick: () => void; // 리턴값이 없는 함수 타입
  isActive?: boolean;
}

// 2. 컴포넌트에 적용 (제네릭이나 매개변수 타입으로)
const MyButton = ({ label, onClick, isActive }: ButtonProps) => {
  return (
    	<button className = {isActive ? 'blue' : 'bray'} onClick={onClick}>
			{label}
		</button>
  );
};

B. API 통신 및 데이터 모델 (DTO)

백엔드 서버와 주고받는 JSON 데이터의 '그릇'을 정의한다.

  • 코드 예시:
// 서버에서 오는 JSON 구조 그대로 정의
export interface UserData {
  userId: string;
  name: string;
  role: 'ADMIN' | 'USER'; // Enum처럼 사용 가능 (리터럴 타입)
}

// axios 호출 시 제네릭으로 주입
const fetchUser = async () => {
  const { data } = await axios.get<UserData>('/api/user/1');
  // 여기서 data. 까지만 쳐도 userId, name, role이 자동완성 됨
  return data;
}

C. 상태 관리 (State & Store)

화면에 렌더링되는 동적인 데이터의 초기값과 허용 타입을 지정합니다.
useStateZustnad 스토어를 만들 때 사용한다.

  • 용도: 변하는 데이터의 초기값과 허용 타입 지정
  • React useState 예시:
// useState<타입>(초기값)
const [userList, setUserList] = useState<UserData[]>([]);
// userList는 무조건 UserData 객체의 배열이어야 함.
// 다른 걸 넣으려고 하면 에러 발생

- Zustand Store 예시:

interface AuthStroe {
  isLoggedIn: boolean;
  login: () => void;
} 

// create<인터페이스> 형태로 사용
const useAuthStore = create<AuthStore>((set) => ({
  isLoggedIn: false,
  login: () => set({ isLoggedIn: true }),
}));

D. 이벤트 핸들링(Event Object)

클릭, 입력, 폼 제출 시 발생하는 Event 객체의 타입을 지정한다.

  • 용도: e.target이 어떤 HTML 요소인지 명시하여, 내부 속성(value 등)에 안전하게 접근합니다.
  • 코드 예시:
// HTMLInputElement에서 발생한 변경 이벤트라고 명시
const handleInputChage = (e: React.ChageEvent<HTMLInputElement>) => {
  // 타입들을 지정했으므로 e.target.value가 문자열을 보장받음
  consoel.log(e.target.value);
};
profile
Good Luck!

0개의 댓글