TypeScript의 typeof 연산자

TypeScript를 사용하다보면 typeof 연산자(JavaScript에도 존재하는)를 자주 마주치게 된다. TypeScript에서 typeof 는 두 가지 문맥에서 사용된다.

  1. JavaScript의 런타임 typeof 연산자
  2. TypeScript의 타입 연산자로서의 typeof

1. JavaScript의 런타임 typeof 연산자

typeof는 피연산자의 데이터 타입을 나타내는 문자열을 반환한다.

let value = "hello";
console.log(typeof value); // "string"

let number = 32;
console.log(typeof number); // "number"

let func = () => {};
console.log(typeof func); // "function"

반환되는 값은 JavaScript의 기본 데이터 타입 (boolean, number, bigint, string, symbol, null, undefined)과 function, object 이다.

2. TypeScript의 타입 연산자 typeof

TypeScript에서는 typeoftype 문맥에서도 사용할 수 있다. 이때는 역할이 달라진다.

const user = {
  name: "John",
  age: 30,
  isAdmin: true
};

const v_user = typeof user; // object
type User = typeof user;
// 결과:
// type User = {
//   name: string;
//   age: number;
//   isAdmin: boolean;
// }

위 예시의 v_userconst 키워드로 선언된 변수에서 사용됐다. 따라서 값이 할당되야 하므로 user의 런타입 타입을 가리키는 'object'를 반환한다. 하지만 type 키워드 뒤에서 사용된 typeof는 타입스크립트의 타입을 반환한다.

typeof는 값에서 타입을 추출할 때만 사용하도록 한다. 이미 타입인 것에서 사용할 때는 에러가 난다.

// 잘못된 사용
type MyString = string;
type Wrong = typeof MyString; // 오류!

// 올바른 사용
const myString = "hello";
type Correct = typeof myString; // string

typeof 활용

1. 배열에서 유니온 타입 추출

const colors = ["red", "green", "blue"] as const;
type Colors = typeof colors[number];
// type Colors = "red" | "green" | "blue"

2. 객체 타입 추출

// without as const
const config = {
  endpoint: "api.example.com",
  port: 3000
};
type Config = typeof config;
// type Config = {
//   endpoint: string;
//   port: number;
// }

// with as const
const config = {
  endpoint: "api.example.com",
  port: 3000
} as const;
type Config = typeof config;
// type Config = {
//   readonly endpoint: "api.example.com";
//   readonly port: 3000;
// }

as const와 함께 사용하면 readonly가 붙어서 추출된다.

3. 함수 타입 추출

유틸리티 타입 ReturnTypeParameters를 활용하여 함수의 매개변수와 반환 타입을 추출할 수 있다.

function createUser(name: string, age: number) {
  return { id: Date.now(), name, age };
}

type User = ReturnType<typeof createUser>;
// type User = {
//   id: number;
//   name: string;
//   age: number;
// }

type Param = Parameters<typeof createUser>
// type Param = {
//   name: string;
//   age: number;
// }

🔎 참조