타입스크립트 타입 종류 / 타입스크립트 기본 타입 정의 방법
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
인터페이스, 클래스, 제네릭 타입 등 심화 타입들을 정의할 수 있습니다.