타입스크립트 타입 종류 / 타입스크립트 기본 타입 정의 방법

TypeScript 기본 타입 종류

기본 원시 타입 (Primitive Types)

// 문자만 저장 허용
let 변수명: string = "문자";

// 숫자만 저장 허용 (정수, 실수 모두 포함)
let 변수명: number = 숫자;

// 아주 큰 정수 저장 허용
let 변수명: bigint = 123456789012345678901234567890n;

// 참/거짓만 저장 허용
let 변수명: boolean = true;

// null 값만 저장 허용
let 변수명: null = null;

// undefined 값만 저장 허용 (값이 할당되지 않음)
let 변수명: undefined = undefined;

// 고유한 식별자만 저장 허용
let 변수명: symbol = Symbol("id"); // 고유한 식별자 생성 함수 (객체 키로 사용 가능)

원시 타입 변수는 객체 참조가 아닌, 단일 프리미티브 값 자체를 저장합니다.
‘: 타입명’ 처럼 타입 주석 (타입 어노테이션) 형태로 변수 타입을 정의할 수 있습니다.

리터럴 타입

let 변수명: 값 = 값;

리터럴 타입은 특정 프리미티브 타입 값 하나만 허용하는 타입입니다.

number 리터럴 타입은 number 타입의 하위 타입이므로, number 타입 변수에 할당 가능합니다.

배열 타입 (Array)

// 타입 어노테이션 문법으로 배열 타입 정의
let 변수명: number[] = [1, 2, 3];
let 변수명: string[] = ["문자1", "문자2"];

// 제네릭 문법으로 배열 타입 정의
let 변수명: Array<boolean> = [true, false];

// 유니온 타입 배열 정의 (다양한 타입 값 저장 배열)
let 변수명: (string | number)[] = ["문자", 30, 40];

배열은 주로 동일한 타입 값들의 집합입니다.
다양한 타입 값을 저장할 수 있는 유니온 타입 배열도 정의 가능합니다.

다차원 배열 정의 방법

let 변수명: number[][] = [
  [1, 2, 3],
  [4, 5]
]

number 타입 변수를 담는 2차원 배열 예시입니다.

배열 값 추가 및 제거 방법

// 배열 값 추가
배열명.push(값);

// 배열 값 삭제
배열명.pop();

위와 같이 배열 값을 추가하거나 삭제할 수 있습니다.

튜플 타입

let 변수명: [string, number] = ["나이", 30];

튜플은 다른 타입을 함께 저장할 수 있고, 길이와 타입이 고정된 배열입니다.
튜플도 배열이므로, push/pop 함수 사용 가능하지만 타입 체크가 안될 수 있어 주의가 필요합니다.

튜플 요소를 갖는 배열 정의 방법

const 변수명: [string, number][] = [
  ["홍길동", 1],
  ["김지후", 2],
  ["한빛나", 3]
]

string, number 타입 순서의 튜플을 담는 2차원 배열 예시입니다.

객체 타입 (Object)

// 객체 리터럴 타입 정의
let 변수명: {
  id?: number; // ? : 옵셔널 프로퍼티 (있어도 되고, 없어도 됨)
  name: string; // 필수 프로퍼티
  readonly pw: string; // 읽기 전용 프로퍼티 (값 수정 불가)
} = {
  id: 1,
  name: "오시후",
  pw: '!@#asj'
}

// 객체 속성 접근 가능
변수명.id;

객체 타입을 갖는 변수는 각 프로퍼티명, 프로퍼티 타입을 명시해야 합니다.

객체 타입은 모든 필드를 포함하고, 추가 프로퍼티가 있는 타입이 서브 타입입니다.

타입 별칭으로 객체 타입 정의

// 타입 별칭 정의
type 타입별칭명 = {
  id: number;
  name: string;
  pw: string;
}

// 타입 별칭으로 객체 타입 정의
let 변수명1: 타입별칭명 = {
  id: 1,
  name: "오시후",
  pw: '!@#asj'
}
let 변수명2: 타입별칭명 = {
  id: 2,
  name: "한지연",
  pw: 'fgh%$2!'
}

타입 별칭 정의 후, 동일한 객체 타입을 여러 객체에 재사용할 수 있습니다.
중복된 타입 정의 로직을 줄일 수 있다는 장점이 있습니다.

인덱스 시그니처 문법으로 객체 타입 정의

type 타입별칭명 = {
  [key: string]: number;
  키1: number // 고정 프로퍼티 작성 가능 (변수 선언 시 키1 값이 필수인 경우)
}

let 변수명: 타입별칭명 = {
  키1: 1,
  키2: 2,
  키3: 3
}

키, 값 타입이 모두 동일하게 들어오는 경우 인덱스 시그니처를 활용하면 좋습니다.
키 타입이 string이고, 값 타입이 number인 프로퍼티를 모두 허용하는 인덱스 시그니처 예시입니다.

Enum 타입

// 열거형 타입 정의
enum Role {
  ADMIN = 0,
  USER = 1,
  GUEST // 숫자 생략 시 자동 숫자 할당 (+1)
}

// 객체 값으로 열거형 타입 사용
const 변수명 = {
  name: "김정호",
  role: Role.ADMIN
}

열거형으로 값 집합을 정의합니다.
enum 타입은 컴파일 시 양방향 매핑이 된 JavaScript 객체로 변환됩니다.

any 타입

// 모든 타입 허용하는 any 타입 변수 정의
let 변수명:any = 10;

// 모든 타입 값 저장 가능
변수명 = "10";
변수명 = () => {};

// 다른 타입 변수에 any 타입 변수 저장 가능
// 컴파일 시 정상, 런타임 에러 발생 가능
let num: number = 12;
num = 변수명;

모든 타입 값을 허용해서, 특정 변수 타입을 모를 때 사용할 수 있는 타입입니다.
타입 검사를 하지 않으므로 런타임 에러가 발생할 수 있어 사용이 지양되는 타입입니다.

any 타입 변수는 모든 타입 변수에 할당할 수 있고,
모든 타입 변수를 할당 받을 수 있는 특수한 타입입니다.

unknown 타입

// 모든 타입 허용하는 unknown 타입 변수 정의
let 변수명: unknown = 값;

// 모든 타입 값 저장 가능
변수명 = "";
변수명 = 1;
변수명 = () => {};

// 다른 타입 변수에 unknown 타입 변수 저장 불가
let num: number = 12;
num = 변수명;

// 타입 정제 시, 다른 타입 변수에 unknown 타입 변수 저장 가능
if (typeof 변수명 === "number") {
  num = 변수명;
}

모든 타입 값을 허용하지만, 다른 타입에 할당 시 타입 검사가 진행되는 타입입니다.
특정 변수 타입을 모를 때 any 타입보다 unknown 타입 사용이 더 권장됩니다.

unknown은 모든 타입의 슈퍼 타입이어서 어떤 타입 변수든 할당할 수 있지만,
모든 서브 타입 변수에는 타입 검사 없이 unknown 타입을 직접 할당할 수 없습니다.

void 타입

// 함수 반환 값 없음 명시
function 함수명(): void {
  console.log("로그 출력");
}

// 변수 값 없음 명시
let 변수명: void;

변수명 = 1; // 변수 값 지정 불가
변수명 = undefined; // 변수 값 undefined 저장 가능

void 타입은 아무것도 없음을 의미하는 타입입니다.
주로 void 변수보다는 반환값이 없는 함수로 사용됩니다.

void 타입은 undefined 타입의 슈퍼 타입이므로, undefined 타입 값을 할당할 수 있습니다.
void 타입 변수는 undefined 값을 가지기 때문에, undefined 타입에도 할당 가능합니다.

never 타입

// 함수 반환 값 존재할 수 없음 명시
function 함수명(): never {
  while (true) {}
}

// 변수 값 존재할 수 없음 명시
let 변수명: never;

// 모든 변수 값 할당 불가 (전부 에러 발생)
변수명 = 1;
변수명 = {};
변수명 = undefined;
변수명 = null;

반환 값을 절대 반환하지 않는 함수, 예외 발생 함수 등에 사용하는 타입입니다.

never 타입 변수는 any 타입 등 어떤 타입 값도 직접 할당할 수 없는 공집합입니다.
모든 타입의 하위 타입인 never 타입 변수는 어떤 타입 변수에든 할당할 수 있습니다.
never 타입은 다른 타입과 유니온 타입으로 구성되면 생략됩니다.


대수 타입

여러 타입을 조합해 만드는 새로운 타입입니다.

합집합 타입 (Union 타입)

let 변수명: (string | number) = 값;

// Union 타입을 이용한 배열 타입 정의
let 변수명: (number | string | boolean)[] = [1, "hello", true];

여러 타입 중 하나를 만족하면 저장할 수 있는 유니온 타입 예시입니다.

유니온 타입 객체 정의 방법

type Dog = {
  name: string;
  color: string;
}

type Person = {
  name: string;
  language: string;
}

type UnionType = Dog | Person;

// Dog 타입 집합에 포함되므로 선언 가능
let 변수명: UnionType = {
  name: "",
  color: "",
};

// Person 타입 집합에 포함되므로 선언 가능
let 변수명: UnionType = {
  name: "",
  language: "",
};

// Dog 타입, Person 타입 교집합에 포함되므로 선언 가능
let 변수명: UnionType = {
  name: "",
  color: "",
  language: "",
}

// Dog 타입, Person 타입 집합 등 어디에도 포함되지 않으므로 선언 불가
let 변수명: UnionType = {
  name: ""
};

Union 타입을 사용한 객체 정의 방법 예시입니다.

서로소 유니온 타입 (Tagged Union Type)

type Admin = {
  tag: "ADMIN";
  name: string;
  kickCount: number;
}

type Member = {
  tag: "MEMBER";
  name: string;
  point: number;
}

type Guest = {
  tag: "GUEST";
  name: string;
  visitCount: number;
}

// 서로소 유니온 타입 (서로소 관계의 타입들을 묶음)
type User = Admin | Member | Guest;

function login(user: User) {
  if (user.tag === "ADMIN") {
    // 어드민 로그인 처리
  } else if (user.tag === "MEMBER") {
    // 회원 로그인 처리
  } else {
    // 게스트 로그인 처리
  }
}

서로소 유니온 타입은 서로 교집합이 없는 타입들로 만든 유니온 타입입니다.
각 타입에 tag 등 string 리터럴 타입 프로퍼티를 추가하면, 타입 간 교집합이 없게 됩니다.
이러한 서로소 유니온 타입은 tag 값을 기준으로 타입을 좁혀서 처리할 수 있습니다.

// 한 타입에 모두 정의하여 옵셔널 프로퍼티 남발하는 예시
type BadUser = {
  tag: "ADMIN" | "MEMBER" | "GUEST";
  name: string;
  kickCount?: number;
  point?: number;
  visitCount?: number;
};

위와 같이, 각 타입을 하나의 타입에 몰아서 정의하는 것보다 분리하여 정의하는 것이 안전합니다.

교집합 타입 (Intersection 타입)

type Admin = { role: "admin" };
type User = { name: string };

// 교집합 타입 정의
type AdminUser = Admin & User;

const person: AdminUser = {
  role: "admin",
  name: "지후"
};

여러 타입의 모든 속성을 포함해야 저장할 수 있는 인터섹션 타입 예시입니다.

인터섹션 타입 객체 정의 방법

type Dog = {
  name: string;
  color: string;
}

type Person = {
  name: string;
  language: string;
}

type IntersectionType = Dog & Person;

// Dog 타입, Person 타입 교집합에 포함되므로 선언 가능
let 변수명: IntersectionType = {
  name: "",
  color: "",
  language: ""
}

Intersection 타입을 사용한 객체 정의 방법 예시입니다.


함수 타입

함수 타입 정의

// 함수 매개변수 타입 정의
function 함수명(매개변수명1: string, 매개변수명2?: number) {
  
}

// 함수 반환 값 타입 정의
function 함수명(): string {
  return "값";
}

// 화살표 함수 타입 정의
const 함수명 = (매개변수명1: string, 매개변수명2: number): 반환타입 => {

}

함수의 필수 매개변수 타입, 반환값 타입 지정이 가능합니다.
매개변수명 뒤에 ?를 붙이면, 선택적 매개변수가 되어 값을 전달하지 않아도 됩니다.
선택적 매개변수는 필수 매개변수 앞에 추가할 수 없습니다.

REST 파라미터 타입 정의

// 튜플 타입으로 파라미터 수 제한
function getSum(...rest: [number, number, number]) {
  let sum = 0;
  rest.forEach((it) => (sum += it));

  return sum;
}

getSum(1,2,3);
// number 배열 타입으로 파라미터 수 제한X
function getSum(...rest: number[]) {
  let sum = 0;
  rest.forEach((it) => (sum += it));

  return sum;
}

getSum(1,2,3);
getSum(1,2,3,4,5);

여러 파라미터를 REST 배열에 받을 수 있는 REST 파라미터 타입을 지정할 수 있습니다.
REST 파라미터는 ES6부터 도입된 Javascript 문법입니다.

함수 타입 표현식

// 함수 타입 표현식으로 함수 타입 별칭 정의
type 함수타입명 = (매개변수명1: number, 매개변수명2: string) => 반환타입;

// 함수 타입 별칭으로 함수 타입 정의
const 함수명: 함수타입명 = (a, b) => a + b;

// 함수 정의 시 함수 표현식 직접 작성도 가능
const 함수명: (매개변수명1: number, 매개변수명2: string) => 반환타입 = (a, b) => a + b;

함수 타입 표현식 문법으로 함수 타입 별칭을 정의하여 재사용할 수 있습니다.

함수 호출 시그니처

// 함수 호출 시그니처로 타입 별칭 정의
type 함수타입명 = {
  (매개변수명1: number, 매개변수명2: string): 반환타입; // 함수 호출 시그니처 문법
  프로퍼티명3: string; // 함수도 객체이기 때문에, 함수 프로퍼티 추가 정의 가능
}

// 함수 타입 별칭으로 함수 타입 정의
const 함수명: 함수타입명 = (a, b) => a + b;

// 함수 실행
함수명(1, "2"); // 함수 타입에 맞는 매개변수 없이 호출 시 에러

// 프로퍼티 값 할당
함수명.프로퍼티명3 = "값";

// 함수 프로퍼티 접근
함수명.프로퍼티명3

함수 호출 시그니처 문법으로도 함수 타입 별칭을 정의하여 재사용할 수 있습니다.
변수가 함수처럼 호출되면서 동시에 객체의 속성도 가질 수 있는 하이브리드 타입을 정의할 때 사용합니다.

함수 타입 호환성

함수 타입은 매개변수 타입, 반환값 타입이 모두 호환되는 다른 타입 함수도 할당받을 수 있습니다.

매개변수 타입 호환성

type A = (매개변수명: number) => void;
type B = (매개변수명: 10) => void;

let a: A = () => {};
let b: B = () => {};

// 매개변수 number 타입 a 함수에
// 매개변수 number 리터럴 타입 b 함수 할당 불가능
a = b;

// 매개변수 number 리터럴 타입 b 함수에
// 매개변수 number 타입 a 함수 할당 가능
b = a;

더 넓은 타입 매개변수를 받는 함수에 좁은 타입 매개변수를 받는 함수는 할당할 수 없습니다.
객체 타입 비교에서는 프로퍼티가 많을수록 좁은 타입으로 간주됩니다.

type A = (매개변수명1: number, 매개변수명2: string) => void;
type B = (매개변수명1: number) => void;

let a: A = (매개변수명1, 매개변수명2) => {};
let b: B = (매개변수명1) => {};

// 매개변수 수가 많은 A 타입 함수에
// 매개변수 수가 적은 B 타입 함수 할당 가능
a = b;

// 매개변수 수가 적은 B 타입 함수에
// 매개변수 수가 적은 A 타입 함수 할당 불가능
b = a;

각 함수 타입 매개변수 수가 다른 경우, 매개변수가 많은 함수 타입에 매개변수가 적은 타입 할당은 가능합니다.

반환값 타입 호환성

type A = () => number;
type B = () => 10;

let a: A = () => 10;
let b: B = () => 10;

// 반환값 number 타입 a 함수에
// 반환값 number 리터럴 타입 b 함수 할당 가능
a = b;

// 반환값 number 리터럴 타입 b 함수에
// 반환값 number 타입 a 함수 할당 불가능
b = a;

함수 타입 호환성 체크 시, 반환값 타입은 업캐스팅 불가하고 다운캐스팅 가능합니다.

함수 오버로딩

// TypeScript 오버로드 시그니처 정의
// 함수가 호출될 수 있는 다양한 매개변수 형태 선언
function 함수명(a: number, b: number): number;
function 함수명(a: string, b: string): string;

// 실제 구현부 (하나만 작성 가능)
// 구현 시그니처 매개변수 타입들은 함수 호출 시 타입 판별에 영향X
// 타입 안전성은 오버로드 시그니처에서만 보장
function 함수명(a: any, b: any): any {
  return a + b;
}

// 컴파일 된 Javascript 함수 예시
function 함수명(a, b) {
  return a + b;
}

함수 오버로딩은 Javascript에서 지원되지 않고, Typescript에서 문법적으로만 지원됩니다.
Typescript에서 작성한 오버로드는 컴파일 시 Javascript 함수 1개로 변환됩니다.

함수 오버로딩 시 매개변수 수가 다른 경우

// 오버로드 시그니처
function 함수명(a: number): void;
function 함수명(a: number, b: number, c: number): void;

// 실제 구현부 (구현 시그니처)
function 함수명(a: number, b?: number, c?: number) {
  if (typeof b === 'number' && typeof c === 'number') {
    console.log(a + b + c);
  } else {
    console.log(a);
  }
}

// 함수 호출 예시
함수명(1);
함수명(1, 2, 3);

// 오버로드 시그니처에 없는 매개변수 수로는 호출 불가
함수명(1, 2);

// 컴파일 된 Javascript 코드 예시
function 함수명(a, b, c) {
  if (typeof b === 'number' && typeof c === 'number') {
    console.log(a + b + c);
  } else {
    console.log(a);
  }
}

함수 오버로딩 시 매개변수 수가 다른 경우, 구현부는 선택적 매개변수로 작성해야 합니다.


타입스크립트 고급 타입 정리

https://0songha0.github.io/web-dev/2025-07-11-1
인터페이스, 클래스, 제네릭 타입 등 심화 타입들을 정의할 수 있습니다.