[TS] 타입스크립트 모든 타입 한 번에 정리

타입스크립트에는 다양한 타입들이 존재합니다.

이번 글에서는 타입스크립트에서 지원하는 주요 타입을 정리해 볼게요. 🙂



01


원시 타입 (Primitive Type)

동시에 하나의 값만 저장하는 타입입니다.

📌 타입 주석 (Type Annotation): 변수명 뒤에 :을 붙여 타입을 지정하는 문법입니다.

1. 숫자 타입 (number)

타입스크립트에서 숫자를 다루는 모든 값은 number 타입으로 정의됩니다.

let num1: number = 123;
let num2: number = -123;
let num3: number = 0.123;
let num4: number = -0.123;
let num5: number = Infinity;
let num6: number = -Infinity;
let num7: number = NaN;

 

2. 문자열 타입 (string)

문자열은 string 타입으로 선언할 수 있습니다.

let str1: string = "hello";
let str2: string = 'hello';
let str3: string = `hello`;
let str4: string = `hello ${num1}`;

 

3. 불리언 타입 (boolean)

참(true) 또는 거짓(false) 값을 가질 수 있는 타입입니다.

let bool1: boolean = true;
let bool2: boolean = false;

 

4. null과 undefined

타입스크립트(tsconfig)에서는 strictNullChecks가 기본적으로 true로 설정되어 있어 null이나 undefined 값을 엄격하게 검사합니다. 만약 null을 임시로 설정하고 싶다면, strictNullChecks: false로 설정할 수 있습니다.

let null1: null = null;
let unde1: undefined = undefined;

 

5. 리터럴 타입 (Literal Type)

값 그 자체가 타입이 되는 타입입니다. 지정된 값 이외의 값은 넣을 수 없습니다.

let numA: 10 = 10;
let strA: "hello" = "hello";
let boolA: true = true;


02


배열과 튜플

타입스크립트에서는 배열을 다룰 때 다양한 방법을 사용할 수 있습니다.

1. 배열 (Array)

배열을 선언하는 방법은 두 가지가 있습니다.

let numArr: number[] = [1, 2, 3];
let strArr: string[] = ["hello", "world"];
let boolArr: Array<boolean> = [true, false, true]; // 제네릭 문법

📌 제네릭 문법(Generic Syntax): 제네릭(Generics)은 값이 아닌 타입을 변수처럼 사용하는 기능입니다.
즉, 어떤 타입이 들어올지 모를 때, 미리 타입을 정하지 않고 나중에 지정할 수 있도록 하는 것이죠.

 

2. 여러 타입을 포함하는 배열 (Array with Multiple Types)

let multiArr: (number | string)[] = [1, "hello"]; // 유니온 타입

📌 유니온 타입(Union Type): 유니온 타입은 여러 개의 타입을 하나의 변수에 사용할 수 있도록 하는 기능입니다.
즉, 특정 값이 여러 개의 타입 중 하나를 가질 수 있도록 허용하는 것이죠.

 

3. 다차원 배열 (Multidimensional Array)

let doubleArr: number[][] = [[1, 2, 3], [4, 5]];

 

4. 튜플 (Tuple)

튜플은 배열과 비슷하지만, 길이와 타입이 고정된 배열입니다.

튜플을 사용하면 인덱스 위치에 따라 데이터가 명확하게 정해지므로 유용합니다.

let tub1: [number, number] = [1, 2];
let tub2: [number, string, boolean] = [1, "2", true];

const users: [string, number][] = [
  ["김", 1],
  ["이", 2],
  ["박", 3],
  ["최", 4]
];

 

튜플은 길이와 타입이 고정된 배열이지만, 사실상 자바스크립트의 배열로 동작하기 때문에 push나 pop을 사용할 수 있습니다.

하지만, 이렇게 요소를 추가하거나 제거하면 원래 지정된 튜플의 길이와 타입 규칙이 깨질 수 있어 의도한 대로 동작하지 않을 위험이 있습니다.

📌 지정된 타입과 길이를 유지해야 하는 경우, 튜플에서 push나 pop 사용을 피하는 것이 좋습니다.

let tuple: [number, string] = [1, "hello"];
tuple.push(2);  // 추가 가능하지만, 타입스크립트가 막지 않음
console.log(tuple); // [1, "hello", 2] (튜플의 길이가 변함)


03


객체 타입

타입스크립트에서도 객체 타입을 object로 선언할 수 있습니다.
하지만 object 타입을 사용하면 해당 변수가 객체라는 정보만 제공할 뿐, 내부 프로퍼티에 대한 정보는 알 수 없습니다.
따라서, 점 표기법(user.id)으로 특정 프로퍼티에 접근하려 하면 타입스크립트가 이를 알지 못해 오류를 발생시킵니다.

 

📌 다른 언어와의 차이

 

일반적으로 다른 언어(Java, C# 등)에서는 객체의 이름(타입명)을 기준으로 타입을 정하는 명목적 타입 시스템(Nominal Typing)을 사용합니다.
즉, 같은 구조라도 이름이 다르면 서로 다른 타입으로 취급합니다.

반면, 타입스크립트는 객체의 구조(속성과 타입)를 기준으로 타입을 정하는 구조적 타입 시스템(Property Based Type System)을 사용합니다.
즉, 이름이 달라도 구조가 같으면 같은 타입으로 인정되어 더 유연하게 객체를 사용할 수 있습니다.

1. object 타입

객체를 object 타입으로 선언하면 점 표기법으로 프로퍼티에 접근할 수 없습니다.

let user: object = { id: 1, name: "김" };
// user.id // 오류 발생

 

이를 해결하려면 객체 리터럴 타입 (Object Literal Type)을 사용해야 합니다.

let user: { id: number; name: string } = { id: 1, name: "김" };

 

📌 타입스크립트는 구조적 타입 시스템을 사용합니다. 즉, 객체의 프로퍼티 타입을 기반으로 타입을 정의합니다.

 

2. 선택적 프로퍼티 (Optional Property)

?를 사용하면 객체의 특정 속성을 필수가 아닌 선택으로 만들 수 있습니다.

let user: { id?: number; name: string } = { name: "김" };

 

3. 읽기 전용 프로퍼티

readonly 키워드를 사용하면 특정 속성을 수정할 수 없도록 설정할 수 있습니다. 즉, 프로퍼티 값을 변경할 수 없습니다.

let user: { readonly id: number; name: string } = { id: 1, name: "김" };
// user.id = 2; // 오류 발생


03


타입 별칭과 인덱스 시그니처

1. 타입 별칭 (Type Alias)

중복되는 타입 정의를 줄이기 위해 타입 별칭을 사용할 수 있습니다.

type User = { id: number; name: string; birth: string };

let user1: User = { id: 2, name: "김", birth: "02-16" };
let user2: User = { id: 1, name: "이", birth: "11-03" };

 

2. 인덱스 시그니처 (Index Signature)

정해지지 않은 속성 이름을 가질 경우 사용합니다.

type Users = { [key: string]: number };

let scores: Users = {
  김: 100,
  이: 95,
  박: 80
};

모든 키가 string이고, 값이 number인 객체를 정의할 수 있습니다.



04


Enum 타입

타입스크립트에서만 제공하는 열거형 타입입니다.

Enum을 사용하면 값을 숫자나 문자열로 정의할 수 있고, 이 값들 간에 쉽게 참조하고 비교할 수 있습니다.

그리고 Enum은 컴파일 결과에서 사라지지 않는 특이한 타입입니다.

 

✅ enum을 정의할 때, 타입은 다르게 동작합니다.

  • 타입: enum은 기본적으로 해당 enum 타입을 나타냅니다.
    예를 들어, Status라는 enum을 정의했다면, Status는 타입입니다.
  • : enum의 각 항목은 실제 입니다.
    값은 enum 항목이 실제로 어떤 값을 가지는지, 즉 숫자나 문자열 값입니다.

 

📂 숫자형 예시

enum Direction {
  Up = 1,
  Down,
  Left = 5,
  Right
}

let move: Direction = Direction.Up;  // 값은 1, 타입은 Direction
  • Direction타입에서 Up=1, Down=2, Left=5, Right=6의 값을 가집니다.
  • Direction.Up은 1이라는 값이고, move는 Direction 타입을 가집니다.

 

📂 문자열형 예시

enum Status {
  Success = "SUCCESS",
  Error = "ERROR"
}

let result: Status = Status.Success;  // 값은 "SUCCESS", 타입은 Status
  • Status.Success는 "SUCCESS"라는 값이고, result는 Status 타입을 가집니다.
  • 이 경우 Status는 타입이고, Status.Success는 입니다.

 

✅ enum을 타입 정의할 때 값을 넣어서 사용하는 이유는?

  • 가독성: enum을 사용하면 코드의 의미가 명확해져 읽기 쉽다, 왜냐하면 값 대신 이름을 사용하기 때문이다.
  • 타입 안정성: enum을 사용하면 잘못된 값이 할당되는 것을 방지할 수 있다, 왜냐하면 타입이 제한되기 때문이다.
  • 디버깅 용이성: enum을 사용하면 상태를 추적하고 디버깅하기 쉬워진다, 왜냐하면 의미 있는 이름이 값으로 사용되기 때문이다.
  • 확장성: 새로운 값을 추가할 때, enum만 수정하면 코드가 자동으로 확장된다, 왜냐하면 다른 코드 수정 없이 항목만 추가하면 되기 때문이다.


05


Any와 Unknown 타입

1. Any 타입

any 타입은 변수의 타입을 확실히 모를 때 사용됩니다.
이 타입을 사용하면 어떤 값이든 저장할 수 있지만, 타입 검사가 사라지므로 타입스크립트의 장점을 잃게 됩니다.
즉, 타입스크립트의 보호 장치를 해제하는 치트키 같은 느낌이라 가능하면 사용하지 않는 것이 좋습니다.

let value: any;

value = 10;      // 숫자 가능
value = "hello"; // 문자열 가능
value = {};      // 객체 가능
value.toUpperCase(); // 런타임 에러 발생 (타입 체크 안됨)

📌 any를 남발하면 타입스크립트를 사용하는 의미가 없어지므로 주의하세요!

 

2. Unknown 타입

unknown 타입은 any와 비슷하게 어떤 값이든 저장할 수 있습니다. 하지만 사용하려면 반드시 타입을 확인해야 합니다.
즉, "이 변수가 정확히 어떤 타입인지 확인하기 전까지는 아무 작업도 할 수 없다"는 점이 any와 다릅니다.

예를 들어, any 타입을 사용하면 변수 안에 어떤 값이 들어있든 바로 사용할 수 있지만,

unknown 타입을 사용하면 값의 타입을 확인한 후에만 사용할 수 있습니다.

let value: unknown;

value = 10;
value = "hello";

// console.log(value.toUpperCase()); // ❌ 오류 발생 (타입 확인 필요)

if (typeof value === "string") {
  console.log(value.toUpperCase()); // ✅ 정상 작동
}

📌 unknown은 "어떤 값이든 담을 수 있지만, 무턱대고 사용하면 안 된다! 먼저 타입을 확인해야 한다!"는 규칙이 있는 타입입니다.
즉, 안전성을 높이기 위한 any의 대체제라고 보면 됩니다.



06


Void와 Never 타입

1. Void 타입

void는 값을 반환하지 않는 함수의 타입입니다.

우리가 함수에서 값을 반환하지 않겠다고 명확히 표현하려고 할 때 사용해요.

예를 들어, 콘솔에 메시지를 출력하는 함수는 값을 반환하지 않죠. 이때 void를 써서 "나는 값을 주지 않는다"라고 말해주는 거예요.

function sayHello(): void {
  console.log("Hello!");
}

이 함수는 "Hello!"를 출력만 하고 값을 반환하지 않으니까 void를 사용해요.

 

📌 void는 null이나 undefined와 다르게, "이 함수는 결과를 돌려주지 않는다"는 걸 명확하게 표현하는 타입입니다.
즉, return을 쓰지 않는 함수의 타입이라고 생각하면 됩니다.

 

2. Never 타입

never는 결코 정상적으로 끝나지 않는 함수를 의미해요.

예를 들어, 무한 루프에 빠지거나, 에러를 던져서 함수가 종료되지 않는 경우에 사용해요.

함수가 결코 종료되지 않거나, 값을 반환하지 않거나, 예외를 던질 때 그걸 정확하게 타입으로 표현하려고 사용합니다.

 

✅ 오류를 발생시키는 함수는 정상적으로 종료되지 않으므로 never 타입을 가집니다.

function throwError(message: string): never {
  throw new Error(message); // 여기서 코드가 종료됨
}

 

무한 루프를 도는 함수도 never 타입을 가집니다.

function infiniteLoop(): never {
  while (true) {
    console.log("이 함수는 끝나지 않음!");
  }
}

📌 never는 실행이 종료되지 않는 함수나, 절대 발생할 수 없는 상황을 나타낼 때 사용됩니다.



07


마무리

타입스크립트에는 다양한 타입이 있으며, 이를 적절히 사용하면 코드의 안정성과 가독성을 높일 수 있습니다.

  • 원시 타입(Primitive Type) → 숫자, 문자열, 불리언 등 기본적인 데이터 타입
  • 배열(Array) & 튜플(Tuple) → 여러 개의 값을 다룰 때 사용, 튜플은 길이와 타입이 고정됨
  • 객체(Object) → 구조적 타입 시스템을 사용하며, 선택적(?) 및 읽기 전용(readonly) 속성을 지원
  • 타입 별칭(Type Alias) & 인덱스 시그니처(Index Signature) → 중복을 줄이고 유동적인 객체 구조를 정의하는 데 사용
  • 열거형(Enum) → 여러 값을 의미 있는 이름으로 정의하는 타입
  • any vs unknown
    • any → 모든 타입 허용하지만, 타입 검사가 없으므로 지양하는 것이 좋음
    • unknown → 모든 타입 허용하지만, 사용 전 타입 검사가 필요하여 any보다 안전한 선택
  • void vs never
    • void → 값을 반환하지 않는 함수의 반환 타입
    • never → 함수가 정상적으로 종료되지 않거나 실행될 수 없는 경우에 사용

📌 타입스크립트의 강점은 "명확한 타입 정의를 통해 코드의 안정성을 높이는 것"입니다.