0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

type-challenges 中級編13: RequiredByKeys、Mutable、OmitByType

はじめに

GitHubのtype-challengesリポジトリは、TypeScript型システムの理解を深めるための型クイズ問題集です。高品質な型を作成することで、バグを減らし、プロジェクトの保守性を向上させることができます。今回も中級編から3つの問題に挑戦します。

1. RequiredByKeys

この課題では、ジェネリック型 TK を受け取り、K に指定されたプロパティのみを必須にする型を実装します。K が指定されていない場合は、全てのプロパティを必須にします。

interface User {
  name?: string
  age?: number
  address?: string
}

type UserRequiredName = RequiredByKeys<User, 'name'> // { name: string; age?: number; address?: string }

私の回答

type MergeObj<T> = {
  [k in keyof T]: T[k]
}

type RequiredByKeys<T, K = keyof T> = MergeObj<{
  [k in keyof T as k extends K ? never : k]: T[k]
} & {
  [k in Exclude<keyof T, Exclude<keyof T, K>>]: T[k] extends infer P | undefined ? P : never
}>

解き方

  • 前回解いたPartialByKeys と同様に、まず K に指定されたプロパティを除外したオブジェクト型を生成し、次に K に指定されたプロパティのみを必須にしたオブジェクト型を生成します。
  • 最後にこれらのオブジェクト型をマージして、指定されたプロパティのみが必須になるようにします。

いやなんか無駄な記述多すぎる感、、

他の人の回答も見てみるとこんな回答がありました。

type RequiredByKeys<
  T, 
  K extends keyof T = keyof T,
  O = Omit<T, K> & { [P in K]-?: T[P] }
> = { [P in keyof O]: O[P] }

Omitのことを忘れていました、、
{ [P in K]-?: T[P] }
-? でオプショナル消せるのかよ、、、、

2. Mutable

この課題では、オブジェクト型 T の全てのプロパティをミュータブル(非読み取り専用)にする型を実装します。

interface Todo {
  readonly title: string
  readonly description: string
  readonly completed: boolean
}

type MutableTodo = Mutable<Todo> // { title: string; description: string; completed: boolean; }

私の回答

type Mutable<T> = T extends Readonly<Array<unknown>> ?
  T extends Readonly<[...infer A]> ? A : never
: {
  [k in Exclude<keyof T, Exclude<T,''>>]: T[k]
}

これも無駄な記述多すぎる感がありますね、、

他の人の回答

type Mutable<T> = {
  -readonly [K in keyof T]: T[K]
}

解き方

  • Mutable は、プロパティを再定義して、readonly 修飾子を削除することで実装できます。
  • 他の人の回答のように、-readonly 修飾子を使用すると、全てのプロパティをミュータブルにすることができます。

いやreadonly-readonlyで消せるんかい!!

3. OmitByType

この課題では、ジェネリック型 T から、型 U に割り当て可能なプロパティを除外する型を実装します。

type OmitBoolean = OmitByType<{
  name: string
  count: number
  isReadonly: boolean
  isEnable: boolean
}, boolean> // { name: string; count: number }

私の回答

type OmitByType<T, U> = {
  [k in keyof T as T[k] extends U ? never : k ]: T[k]
}

解き方

  • OmitByType は、PickByType の逆の操作を行います。
  • プロパティの型が U に割り当て可能かどうかをチェックし、割り当て可能なプロパティを除外します。

これはいつものasでどうにかなりますね。

まとめ

これらの課題を通じて、TypeScriptの型システムをより深く理解することができます。特にテンプレートリテラル型や再帰的な型の使用法について学ぶことで、より柔軟で強力な型を作成するスキルが身につきます。ぜひこれらの課題に挑戦して、型の理解を深めてください。

参考記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?