본문으로 건너뛰기
김신건의 로그

[TypeScript] Primitive Types

· 수정 · 📖 약 2분 · 883자/단어 #typescript #types #primitive #language
TS Primitive Types, TypeScript primitive, TypeScript string, TypeScript number, TypeScript boolean, TypeScript unknown, TypeScript never, TypeScript any, TypeScript void, TypeScript symbol, TypeScript bigint

정의

Primitive Types 는 TypeScript 의 가장 기본 타입 계열입니다. JavaScript 의 7가지 primitive 값 + 특수 타입 (void, never, unknown, any) 을 포함합니다.

목록

타입값 예시언제
string"hello"문자열
number42, 3.14정수/실수 (double)
booleantrue, false참거짓
bigint9007199254740993n임의 정밀도 정수
symbolSymbol()고유 식별자
nullnull명시적 null
undefinedundefined값 없음
void리턴 없음함수 반환
never없음절대 발생하지 않음
unknown모든 값타입 모름 (안전)
any모든 값타입 검사 해제 (위험)

string

let s: string = "hello";
let s2 = "world";                    // 추론
const name = "kim";                  // literal type: "kim"

// Template literal
let greeting = `Hello, ${name}`;

Literal type: const 로 선언된 문자열은 정확한 문자열 리터럴 타입 이 됩니다.

let a: string = "hello";      // string
const b = "hello";            // "hello" (literal type)

number

let x: number = 42;
let y: number = 3.14;
let z: number = 0xFF;         // 헥스
let w: number = 0b1010;       // 이진
let v: number = 1_000_000;    // 구분자

const PI = 3.14;              // literal 3.14

JavaScript 는 정수/실수 구분 없음. 모두 64-bit double.

boolean

let flag: boolean = true;
const isReady = false;        // literal false

bigint

임의 정밀도 정수. n 접미사.

let big: bigint = 9007199254740993n;
let big2 = BigInt(123);

// number 와 혼합 불가
big + 1;         // 오류
big + 1n;        // OK

언제: DB primary key, blockchain wei, 큰 timestamp.

symbol

고유 식별자. 두 symbol 은 절대 동등하지 않음.

const s1 = Symbol("foo");
const s2 = Symbol("foo");
s1 === s2;    // false

// 객체의 unique key 로
const KEY = Symbol();
const obj = {[KEY]: "value"};

Symbol.iterator, Symbol.asyncIterator 등 well-known symbol 이 프로토콜 정의.

null / undefined

두 값이 유사하지만 미묘하게 다름:

  • undefined: 변수가 초기화되지 않음, 함수 리턴 없음
  • null: 명시적 으로 값 없음
let x: string | null = null;
let y: string | undefined;

if (x != null) {
  x.toUpperCase();    // null 과 undefined 모두 배제
}

strictNullChecks (기본 활성) 하에서는 string 타입에 null/undefined 를 못 넣음. 명시적 union 필요.

void

함수가 아무것도 반환하지 않음:

function log(msg: string): void {
  console.log(msg);
}

const cb: () => void = () => 42;   // OK, void 는 반환 값 무시

void 리턴 타입 함수의 반환값은 사실상 무시 (() => any 와 다름). 콜백 시그니처에 유용.

never

절대 발생하지 않는 값:

function throwError(msg: string): never {
  throw new Error(msg);
}

function loop(): never {
  while (true) {}
}

Exhaustive check

type Shape = {kind: "circle", r: number} | {kind: "square", s: number};

function area(s: Shape): number {
  switch (s.kind) {
    case "circle": return Math.PI * s.r ** 2;
    case "square": return s.s ** 2;
    default:
      const _exhaustive: never = s;    // 새 case 추가 시 컴파일 오류
      return _exhaustive;
  }
}

Discriminated union 의 모든 case 를 다뤘음을 컴파일러가 검증.

never 는 모든 타입의 subtype

type Result = never | number;   // number 로 축약

unknown

타입을 모른다 는 것을 안전하게 표현. any 대체.

let x: unknown = JSON.parse(rawJson);

// 바로 사용 불가
x.toUpperCase();          // 오류

// narrowing 후 사용
if (typeof x === "string") {
  x.toUpperCase();        // OK
}

if (typeof x === "object" && x !== null && "name" in x) {
  console.log(x.name);
}

언제: 외부 데이터 (JSON.parse, API 응답, event.data). 검증 후 좁혀서 사용.

any

타입 검사 해제. 위험.

let x: any = 5;
x = "string";
x.foo.bar();       // 컴파일 통과, 런타임 오류

언제 (제한적으로 허용):

  • 마이그레이션 임시 회피
  • 진짜로 타입을 알 수 없고 검증 안 할 때
  • noImplicitAny: false 는 위험

unknown 이 대개 더 안전한 대안.

Anti-pattern: any[], Record<string, any>, Function 남용.

Union 조합

let id: string | number = "abc";
id = 42;

function print(v: string | number | boolean): void {
  console.log(v);
}

자세한 것은 Union / Intersection 참조.

Literal Type

let status: "pending" | "active" | "closed" = "pending";

type Direction = "north" | "south" | "east" | "west";

function move(dir: Direction): void {
  ...
}

move("north");       // OK
move("northwest");   // 오류
  • Enum 대신 자주 사용됨 (자세한 것은 Enums 참조)
  • 상수의 타입을 그대로 표현

Object literal type

let user: {name: string, age: number} = {name: "kim", age: 30};

// Optional
let config: {debug?: boolean, port: number} = {port: 8000};

// Readonly
let point: {readonly x: number, readonly y: number} = {x: 1, y: 2};
point.x = 5;   // 오류

// Index signature
let scores: {[key: string]: number} = {alice: 90, bob: 85};

Interface 나 type alias 로 이름 붙이는 편이 관용.

Array

let ns: number[] = [1, 2, 3];
let ns2: Array<number> = [1, 2, 3];    // 동일

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

// Readonly
let ro: readonly number[] = [1, 2, 3];
ro.push(4);       // 오류

Tuple

let pair: [string, number] = ["a", 1];
pair[0].toUpperCase();
pair[1].toFixed(2);

// Optional
let mixed: [string, number?] = ["a"];

// Named tuple
let range: [start: number, end: number] = [0, 100];

// Rest in tuple
let strs: [string, ...number[]] = ["a", 1, 2, 3];

자주 하는 실수

실수 1: Number (대문자)

let x: Number = 5;    // Boxed wrapper 타입, 사용 안 함
let y: number = 5;    // 정답 (primitive)

String, Boolean, Object 도 마찬가지. 대문자는 wrapper 객체 타입, 소문자가 primitive.

실수 2: Object

let x: Object = {};   // 거의 아무거나
let y: object = {};   // primitive 아닌 것
let z: {} = {};       // null/undefined 제외 모든 것

이 셋은 미묘하게 다르며 대개 원하는 건 명시적 shape ({name: string}) 이거나 Record<K, V>.

실수 3: any 남용

function f(x: any): any {
  return x.foo();
}

이 함수 안에서는 무엇이든 가능. 호출부에도 any 가 퍼짐. unknown 이나 정확한 시그니처로 대체.

함정

WARNING

any 는 감염됩니다. any 를 리턴하는 함수의 결과는 any. any 로부터 파생된 것들 모두 any. 초기부터 unknown 을 습관화.

CAUTION

null vs undefined. API 응답에서 필드가 없음 (undefined) 과 명시적 null 은 다름. 둘 다 처리하려면 x ?? default (nullish coalescing).

WARNING

Number.isNaN 을 씁시다. 전역 isNaN("abc") 은 true (문자열도 강제 형변환). Number.isNaN 만 정확한 NaN 검사.

IMPORTANT

bigint 는 JSON 안 됨. JSON.stringify(1n) 오류. 문자열 직렬화 후 파싱 필요.

CAUTION

unknown narrowing 을 잊지 마세요. unknown 은 안전하지만 그만큼 사용 전에 검증 필수.

관련 위키

이 글의 용어 (11개)
[Javascript] BigIntjavascript
정의 는 임의 정밀도 정수. 를 넘어가는 정수를 정확히 표현. ES2020 도입. 사용 상황 | 상황 | 권장 타입 | |:---|:---| | 64-bit 정수 ID (DB의 …
[Javascript] boolean / null / undefinedjavascript
정의 JavaScript 의 3 가지 primitive. - : , - : 의도적인 "없음" - : 자동으로 부여된 "없음" (초기화 안 됨) 사용 상황 | 상황 | 권장 값 /…
[Javascript] NaN / Infinityjavascript
정의 - (Not a Number) : 의미 없는 수치 연산의 결과 - , : 너무 큰/작은 수, 0 으로 나누기 IEEE 754 표준에 따른 특수 값. 타입이지만 특이한 동작.…
[Javascript] Numberjavascript
정의 JavaScript 의 는 IEEE 754 double-precision float (64-bit). 정수와 실수를 같은 타입으로 표현. 정수 안전 범위는 . IEEE 75…
[Javascript] Stringjavascript
정의 JavaScript 의 은 UTF-16 코드 유닛의 불변 시퀀스. 작은따옴표, 큰따옴표, 백틱 (template literal) 으로 작성. 사용 상황 | 상황 | 권장 패…
[TypeScript] Enumstypescript
정의 Enum 은 여러 관련 상수를 하나의 이름 아래 그룹화하는 TypeScript 기능입니다. Numeric enum, string enum, const enum, hetero…
[TypeScript] Interfacestypescript
정의 Interface 는 객체의 shape (형태) 을 정의하는 TypeScript 문법입니다. 필드, 메서드, 인덱스 시그니처, 호출 시그니처를 선언하며, 로 상속하고 dec…
[TypeScript] Type Aliasestypescript
정의 Type Alias 는 타입에 이름을 붙이는 TypeScript 문법 ( ). Interface 는 객체 shape 만 표현하지만, type alias 는 모든 타입 표현식…
[TypeScript] Type Narrowing (Type Guards)typescript
정의 Type Narrowing 은 TypeScript 컴파일러가 제어 흐름 분석 (control flow analysis) 을 통해 특정 위치에서 값의 타입을 더 좁게 추론하는…
[TypeScript] Union & Intersection Typestypescript
정의 - Union Type ( ): A 이거나 B (또는 둘 다) 인 값 - Intersection Type ( ): A 이면서 B 인 값 두 조합은 TypeScript 의 타…
TypeScripttypescript
정의 TypeScript 는 Microsoft 가 2012년 발표한 JavaScript 의 상위 집합 프로그래밍 언어입니다. 정적 타입 시스템, 인터페이스, 제네릭, enum, …

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기