KAKAMU
BlogTag

TypeScript非内蔵の汎用的な型

そもそも

主にtype-challengesに挑戦する過程で学んだ、TypeScript非内蔵の汎用的な型をまとめてみた。

主な依存パッケージ

"devDependencies": {
    "typescript": "5.6.3"
}

オブジェクト

DeepReadOnly

type DeepReadOnly<T> = {
  readonly [K in keyof T]: T[K] extends isPrimitive<T[K]>
    ? T[K]
    : DeepReadOnly<T[K]>
}

DeepRequired

type DeepRequired<T> = {
  [K in keyof T]-?: T[K] extends isPrimitive<T[K]> ? T[K] : DeepRequired<T[K]>
}

DeepPartial

type DeepPartial<T> = {
  [K in keyof T]?: T[K] extends isPrimitive<T[K]> ? T[K] : DeepPartial<T[K]>
}

PickRequired

type PickRequired<T> = Pick<
  T,
  {
    [K in keyof T]: T[K] extends Required<T>[K] ? K : never
  }[keyof T]
>

PickOptional

type PickOptional<T> = Pick<
  T,
  {
    [K in keyof T]: T[K] extends Required<T>[K] ? never : K
  }[keyof T]
>

OmitNever

type OmitNever<T> = {
  [K in keyof T as T[K] extends never ? never : K]: T[K]
}

ValueOf

type ValueOf<T> = T extends Record<string, infer U> ? U : never
 
type ValueOf<T extends Record<string, unknown>> = T[keyof T]

Diff

type Diff<T, U> = Omit<T & U, keyof (T | U)>

配列

UnpackArray

type UnpackArray<T extends any[]> = T extends (infer U)[] ? U : never

NonEmptyArray

type NonEmptyArray<T extends any[]> = [T, ...T[]]

Length

type Length<T extends any[]> = T['length']

First

type First<T extends any[]> = T extends [] ? never : T[0]
 
type First<T extends any[]> = T extends [infer U, ...any[]] ? U : never

Last

type Last<T extends any[]> = [any, ...T][T['length']]
 
type Last<T extends any[]> = T extends [...infer _, infer L] ? L : never

Push

type Push<T extends any[], U> = [...T, U]

Pop

type Pop<T extends any[]> = T extends [...infer I, infer _] ? I : never

Unshift

type Unshift<T extends any[], U> = [U, ...T]

Flatten

type Flatten<T extends any[] | unknown> = T extends []
  ? []
  : T extends [infer First, ...infer Rest]
    ? [...Flatten<First>, ...Flatten<Rest>]
    : [T]

タプル

TupleToUnion

type TupleToUnion<T extends readonly any[]> = T[number]

TupleToObject

type TupleToObject<T extends readonly any[]> = {
  [K in T[number]]: K
}

文字列

Capitalize

type Capitalize<T extends string> = T extends `${infer U}${infer V}`
  ? `${Uppercase<U>}${V}`
  : never

KebabCase

type KebabCase<T extends string> = T extends `${infer U}${infer V}`
  ? V extends Uncapitalize<V>
    ? `${Uncapitalize<U>}${KebabCase<V>}`
    : `${Uncapitalize<U>}-${KebabCase<V>}`
  : never

Trim

type Space = ' ' | '\t' | '\n'
type Trim<T extends string> = T extends
  | `${Space}${infer U}`
  | `${infer U}${Space}`
  ? Trim<U>
  : T

Replace

type Replace<
  T extends string,
  U extends string,
  V extends string,
> = T extends `${infer A}${U}${infer B}` ? `${A}${V}${B}` : T

StringToUnion

type StringToUnion<T extends string> = T extends `${infer U}${infer V}`
  ? U | StringToUnion<V>
  : never

Set

UnpackSet

type UnpackSet<T> = T extends Set<infer U> ? U : never

Map

MapKeys

type MapKeys<T> = T extends Map<infer U, unknown> ? U : never

MapValues

type MapValues<T> = T extends Map<unknown, infer U> ? U : never

関数

Args

type Args<T extends (...args: any) => any> = T extends (...args: infer U) => any
  ? U
  : never

ちょっと特殊な型

isPrimitive

type Primitive = string | number | bigint | boolean | symbol | null | undefined
type isPrimitive<T> = T extends Primitive ? true : false

UnionToIntersection

Union型をIntersection型に変換する型

type UnionToIntersection<U> = (
  U extends any ? (arg: U) => void : never
) extends (arg: infer I) => void
  ? I
  : never

参考:https://qiita.com/suin/items/93eb9c328ee404fdfabc

Equal

二つの型を厳密に等価判定する型

type Equal<X, Y> =
  (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
    ? true
    : false

参考:https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650

Common

二つの型に共通するプロパティを抽出する型(自作)

type Common<
  T extends Record<string, unknown>,
  U extends Record<string, unknown>,
> = Pick<
  T,
  {
    [K in keyof T & keyof U]: Equal<T[K], U[K]> extends true ? K : never
  }[keyof T & keyof U]
>

参考書籍

プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで

参考リンク

type-challenges

Utility Types

サバイバルTypeScript

type-fest

#IT#TypeScript