커스텀 타입 정의의 일반적인 방법

위 코드는 Astro 프로젝트에서 커스텀 타입을 정의하는 일반적인 방법을 보여줍니다. TabTabs 컴포넌트를 @mdx 경로에서 가져와 사용할 수 있습니다.

예제

customType 정의가 어떻게 동작하는지 확인하는 가장 좋은 방법은 Drizzle ORM의 customType 함수를 사용해 Postgres와 MySQL의 기존 데이터 타입을 정의하는 방법을 살펴보는 것입니다.

Postgres 데이터 타입
MySQL 데이터 타입

Serial

import { customType } from 'drizzle-orm/pg-core';

const customSerial = customType(
  {
    dataType() {
      return 'serial';
    },
  },
);

Text

import { customType } from 'drizzle-orm/pg-core';

const customText = customType({
  dataType() {
    return 'text';
  },
});

Boolean

import { customType } from 'drizzle-orm/pg-core';

const customBoolean = customType({
  dataType() {
    return 'boolean';
  },
});

Jsonb

import { customType } from 'drizzle-orm/pg-core';

const customJsonb = (name: string) =>
  customType({
    dataType() {
      return 'jsonb';
    },
    toDriver(value: TData): string {
      return JSON.stringify(value);
    },
  })(name);

Timestamp

import { customType } from 'drizzle-orm/pg-core';

const customTimestamp = customType<
  {
    data: Date;
    driverData: string;
    config: { withTimezone: boolean; precision?: number };
  }
>({
  dataType(config) {
    const precision = typeof config.precision !== 'undefined'
      ? ` (${config.precision})`
      : '';
    return `timestamp${precision}${
      config.withTimezone ? ' with time zone' : ''
    }`;
  },
  fromDriver(value: string): Date {
    return new Date(value);
  },
});

모든 타입의 사용법은 Drizzle ORM에서 정의된 함수와 동일합니다. 예를 들어:

const usersTable = pgTable('users', {
  id: customSerial('id').primaryKey(),
  name: customText('name').notNull(),
  verified: customBoolean('verified').notNull().default(false),
  jsonb: customJsonb('jsonb'),
  createdAt: customTimestamp('created_at', { withTimezone: true }).notNull()
    .default(sql`now()`),
});

타입 정의를 위한 TS-doc

typesparam 정의에 대한 TS-doc을 확인할 수 있습니다.

export type CustomTypeValues = {
  /**
   * 커스텀 컬럼에 필요한 타입으로, 적절한 타입 모델을 추론합니다.
   *
   * 예시:
   *
   * 컬럼이 선택 또는 삽입 후 `string` 타입이 되길 원한다면 `data: string`을 사용하세요. 예를 들어 `text`, `varchar`와 같은 타입입니다.
   *
   * 컬럼이 선택 또는 삽입 후 `number` 타입이 되길 원한다면 `data: number`를 사용하세요. 예를 들어 `integer`와 같은 타입입니다.
   */
  data: unknown;

  /**
   * 데이터베이스 드라이버가 특정 데이터베이스 데이터 타입에 대해 받아들이는 타입을 나타내는 헬퍼입니다.
   */
  driverData?: unknown;

  /**
   * {@link CustomTypeParams}의 `dataType` 생성에 사용될 설정 타입입니다.
   */
  config?: Record;

  /**
   * 커스텀 데이터 타입이 기본적으로 `notNull`이어야 한다면 `notNull: true`를 사용할 수 있습니다.
   *
   * @example
   * const customSerial = customType({
   *    dataType() {
   *      return 'serial';
   *    },
   * });
   */
  notNull?: boolean;

  /**
   * 커스텀 데이터 타입에 기본값이 있다면 `default: true`를 사용할 수 있습니다.
   *
   * @example
   * const customSerial = customType({
   *    dataType() {
   *      return 'serial';
   *    },
   * });
   */
  default?: boolean;
};

export interface CustomTypeParams {
  /**
   * 마이그레이션에 사용되는 데이터베이스 데이터 타입의 문자열 표현입니다.
   * @example
   * ```
   * `jsonb`, `text`
   * ```
   *
   * 데이터베이스 데이터 타입에 추가 파라미터가 필요하다면 `config` 파라미터를 사용할 수 있습니다.
   * @example
   * ```
   * `varchar(256)`, `numeric(2,3)`
   * ```
   *
   * `config`가 특정 타입이 되길 원한다면 {@link CustomTypeValues}에서 config 제네릭을 사용하세요.
   *
   * @example
   * 사용 예시
   * ```
   *   dataType() {
   *     return 'boolean';
   *   },
   * ```
   * 또는
   * ```
   *   dataType(config) {
   *     return typeof config.length !== 'undefined' ? `varchar(${config.length})` : `varchar`;
   *   }
   * ```
   */
  dataType: (config: T['config']) => string;

  /**
   * 사용자 입력과 드라이버 간의 매핑 함수입니다. (선택 사항)
   * @example
   * 예를 들어, `jsonb`를 사용할 때 데이터베이스에 쓰기 전에 JS/TS 객체를 문자열로 매핑해야 합니다.
   * ```
   * toDriver(value: TData): string {
   *   return JSON.stringify(value);
   * }
   * ```
   */
  toDriver?: (value: T['data']) => T['driverData'];

  /**
   * 데이터베이스에서 JS/TS 코드로 데이터를 매핑하는 함수입니다. (선택 사항)
   * @example
   * 예를 들어, `timestamp`를 사용할 때 문자열 Date 표현을 JS Date로 매핑해야 합니다.
   * ```
   * fromDriver(value: string): Date {
   *  return new Date(value);
   * },
   * ```
   */
  fromDriver?: (value: T['driverData']) => T['data'];
}