TypeScriptの型から、プロパティ名を部分一致で抽出したり削除する

TypeScriptで、既存の型から一部のプロパティを、プロパティ名の部分一致で抽出・削除する方法をメモ。

環境

TypeScript v4.7.4 で確認。

プロパティ名の部分一致での抽出・削除方法

テンプレートリテラル内にUnionを用いると、すべての組み合わせの文字列リテラルのUnionとなる。

文字列から型定義が行えるこの機能は、Template Literal Typesというらしい。

TypeScript: Documentation - Template Literal Types

Extract の第2引数に prefix${string} のように指定することで、プロパティ名を部分一致で抽出できる。

Extract の結果を、 Pick に渡してやれば抽出、 Omit に渡してやれば削除できる。

// val1 | val2 | value1 | value2 のUnionになる
type PropertyNames = `${`val${'' | 'ue'}`}${1 | 2}`

// Unionの各値をプロパティ名とした型を用意
type Properties = Record<PropertyNames, string>

// value1 | value2 のUnion
type TargetPropertyNames = Extract<keyof Properties, `value${string}`>

// Record<'value1' | 'value2', string> と同様
type PickProperties = Pick<Properties, TargetPropertyNames>

// Record<'val1' | 'val2', string> と同様
type OmitProperties = Omit<Properties, TargetPropertyNames>

実装例

以下のような type を用意。

type PropertySuffix = 1 | 10 | 100 | 'Value' | 'True' | 'False' | true | false

// { [Key in `string${PropertySuffix}`]: string } & ... と同様
type Properties = Record<`string${PropertySuffix}`, string> &
  Record<`number${PropertySuffix}`, number> &
  Record<`boolean${PropertySuffix}`, boolean>

type PropertyKeys = keyof Properties

任意の文字列での一致

${string}ワイルドカードのように使用できる。

  • 前方一致: prefix${string}
  • 部分一致: ${string}infix${string}
    • infixで指定した文字列が先頭や末尾に存在する場合も対象となる
  • 後方一致: ${string}suffix
// stringで開始するプロパティを抽出
type Type1 = Pick<Properties, Extract<PropertyKeys, `string${string}`>>

// 末尾のeも対象のため、 { string1, string10, string100 } を除いて削除
type Type2 = Omit<Properties, Extract<PropertyKeys, `${string}e${string}`>>

// `False` および `false` を抽出
type Type3 = Pick<Properties, Extract<PropertyKeys, `${string}se`>>

// 3つ以上 ${string} を書くこともできる

// nの後ろに10があるプロパティを抽出
type Type4 = Pick<Properties, Extract<PropertyKeys, `${string}n${string}10${string}`>>

任意の数値での一致

${number} で、数値のみを指定できる。

// { number1, number10, number100 } を抽出
type Type5 = Pick<Properties, Extract<PropertyKeys, `number${number}`>>

true/falseでの一致

これは使う機会がないと思うが、いちおうできるということで。

${boolean} で、 true または false を指定できる。大文字小文字の区別あり。

// { booleantrue, booleanfalse } を抽出
// { booleanTrue, booleanFalse } は対象外
type Type6 = Pick<Properties, Extract<PropertyKeys, `boolean${boolean}`>>

指定文字列や数値での一致

任意のUnionを指定することで、より細かい判定が可能。

// string または number で始まり、数字 or 'Value' or true で終わるものを抽出
type Type7 = Pick<
  Properties,
  Extract<PropertyKeys, `${'string' | 'number'}${number | 'Value' | true}`>
>

振り返り

自分の書いたソースをコードレビューしてもらったときに、「これ何やってんの?」と聞かれたので書いてみた。

ただ、けっこう便利なので使っていたが、いつどこで覚えた方法なのか思い出せない。Stack Overflowで引っかけたのか、どこかのブログでも見たのか。

この記事を書くに際し、公式ドキュメントも見てみたが、${string} が検索しづらく、Template Literal Typesのページ以外見つけられなかった。

何かしら名前がついてそうだが、なんていうんだろう。