生のtypescriptジェネリックのキャメルケースへの方法
31388 ワード
TLDR
今日の挑戦は、Aをタイプすることです
UPPER_CASE
静的文字列camelCase
そして、この変換をオブジェクトキーに再帰的に適用します.プレビュー
ご覧のように、静的なタイプのテキストを
UPPER_CASE
フォーマットcamelCase
. 次に,変換を全オブジェクトキーに再帰的に適用した.You can play with full source code here
TypeScript 4.2は既にベータ版であるので、我々はそれを提供する力を完全に使うために、新しい着信機能の準備をしなければなりません.そこにすべての新しいtypemcripthttps://devblogs.microsoft.com/typescript/announcing-typescript-4-2-beta/
コードに深く飛び込みましょう
事件を変える
UPPER_CASE
キャメルケースには、パーサを使用して大文字を小文字に変換し、不要な文字を取り除く必要があります_
. 文字マッパー
まず最初に、小文字と大文字の間の依存関係を記述する下側/上マッパー型を作成します.
type LowerToUpperToLowerCaseMapper = {
a: 'A'
b: 'B'
c: 'C'
d: 'D'
e: 'E'
f: 'F'
g: 'G'
h: 'H'
i: 'I'
j: 'J'
k: 'K'
l: 'L'
m: 'M'
// ... and so on
}
type UpperToLowerCaseMapper = {
A: 'a'
B: 'b'
C: 'c'
// ... and so on
}
文字列を解析する
読むべき小さなパーサを書かなければなりません
UPPER_CASE
フォーマットし、変換される新しい構造に解析しますcamelCase
. では、テキストパーサーUtil関数から始めましょう.ヘッドレター
このジェネリックは最初の文字を入力し、それを返します.
type HeadLetter<T> = T extends `${infer FirstLetter}${infer _Rest}` ? FirstLetter : never
尾文字
このジェネリックは、最初の1つ以外のすべての文字を入力し、それらを返します.
type TailLetters<T> = T extends `${infer _FirstLetter}${infer Rest}` ? Rest : never
lettertoupper
このジェネリックは、適切な小文字のマッパー構造体を呼び出して1つのcharを変換します.
type LetterToUpper<T> = T extends `${infer FirstLetter}${infer _Rest}`
? FirstLetter extends keyof LowerToUpperToLowerCaseMapper
? LowerToUpperToLowerCaseMapper[FirstLetter]
: FirstLetter
: T
レトルト
type LetterToLower<T> = T extends `${infer FirstLetter}${infer _Rest}`
? FirstLetter extends keyof UpperToLowerCaseMapper
? UpperToLowerCaseMapper[FirstLetter]
: FirstLetter
: T
トウローケース
現在、我々は再帰的に呼び出しているALBEです
HeadLetter
, Tail
and LetterToLower
全体を反復するstring
そして、それらにlowecaseを適用します.
type ToLowerCase<T> = T extends ''
? T
: `${LetterToLower<HeadLetter<T>>}${ToLowerCase<TailLetters<T>>}`
トーセンシクラーゼ
このジェネリックは、最初の文字を大文字と小文字に変換します.
type ToSentenceCase<T> = `${LetterToUpper<HeadLetter<T>>}${ToLowerCase<TailLetters<T>>}`
私たちはすべてのutilsジェネリックで行われているので、最終型の実装に飛び込むことができます.
Uppercasetopascalcase
我々はほとんどそこにいる.今、我々は変換されるジェネリックを書くことができます
CAMEL_CASE
into PascalCase
.type ToPascalCase<T> = T extends ``
? T
: T extends `${infer FirstWord}_${infer RestLetters}`
? `${ToSentenceCase<FirstWord>}${ToPascalCase<RestLetters>}`
: ToSentenceCase<T>
ご存知のように、我々は再帰的に言葉を分割_
区切り文字.各単語に変換Sentencecase
そして、一緒に結合します.Uppercasetocamelcase
最後のステップは使用することです
PascalCase
しかし、最初の単語の小文字を小文字にします.我々は以前に作成されたジェネリックを使用して、ちょうど一緒にそれらを組み合わせる.
export type UpperCaseToCamelCase<T> = `${ToLowerCase<HeadLetter<T>>}${TailLetters<ToPascalCase<T>>}`
かなり素晴らしいとちょっと単純なコード、右?
ケースキーへのケース変換の適用
ここで再帰的に適用される静的な型を作りたい
UpperCaseToCamelCase
オブジェクトネストされたキーへのジェネリック.始める前に、3つのヘルパージェネリックを定義しましょう.
getObjValue
type GetObjValues<T> = T extends Record<any, infer V> ? V : never
この単純なジェネリックは、私たちがRecord<any, T>
ラッパー.キャスト
このジェネリックは、無効な型を渡すためにtypescriptコンパイラをバイパスするのに役立ちます.私たちは、第2のパラメータとして定義される他のタイプにユニオンタイプを「縮小する」ためにキャストを使用します.
type Cast<T, U> = T extends U ? T : any
type T4 = string | number
type T5 = Cast<T4, string>
SwitchKeyValue
私たちは以前定義のジェネリックを使用します
GetObjValues<T>
を値に切り替えます.このジェネリックの目的は、文字列の値をキーに変換することです.
type Foo = SwitchKeyValue<{ a: 'key-a', b: 'key-b' }>
type GetObjValues<T> = T extends Record<any, infer V> ? V : never
export type SwitchKeyValue<
T,
// step 1
T1 extends Record<string, any> = {
[K in keyof T]: { key: K; value: T[K] }
},
// step 2
T2 = {
[K in GetObjValues<T1>['value']]: Extract<GetObjValues<T1>, { value: K }>['key']
}
> = T2
手順全体を2段階にするので、コードを入れ子にしないで、部分的な値を変数に保存することにしました.サブ結果変数は一般的なパラメータのために保存されます.そのtypescript機能のおかげで私は“変数”に変換の結果を“保存”することができますT1
and T2
. これは静的な型をよりネストすることで書く有用なパターンです.すべてがうまくいくので、再帰的な入れ子になったキー変換に飛び込みましょう.
TransformKeyStamelcase
今、我々は全体の記事から芸術の1つの作品にジェネリックを結合します.
type TransformKeysToCamelCase<
T extends Record<string, any>,
T0 = { [K in keyof T]: UpperCaseToCamelCase<K> },
T1 = SwitchKeyValue<T0>,
T2 = {
[K in keyof T1]:T[Cast<T1[K], string>]
}
> = T2
type NestedKeyRevert = TransformKeysToCamelCase<{
FOO_BAR: string
ANOTHER_FOO_BAR: true | number,
}>
ご覧のように、ジェネリックには3つの手順があります
T0
, T1
and T2
変数.第一歩
最初のステップは、キーがUperperCaseケースであり、値がCamelCaseに変換されたキーであるオブジェクト型を作成します
T0 = { [K in keyof T]: UpperCaseToCamelCase<K> },
第二段階
番目のステップは、以前に作成されたジェネリックスイッチとスイッチキーを
T1 = SwitchKeyValue<T0>,
第三段階
第3ステップ接続
T1
からのデータ型T
.T2 = { [K in keyof T1]: T[Cast<T1[K], string>] }
入れ子深い再帰を加える
これを提供するために、値がObjectの型であるかどうかをチェックし、再帰を呼び出すジェネリックを作成します.
type CallRecursiveTransformIfObj<T> = T extends Record<any, any> ? TransformKeysToCamelCase<T> : T
を返します.
type TransformKeysToCamelCase<
T extends Record<string, any>,
T0 = { [K in keyof T]: UpperCaseToCamelCase<K> },
T1 = SwitchKeyValue<T0>,
T2 = { [K in keyof T1]: CallRecursiveTransformIfObj<T[Cast<T1[K], string>]> }
> = T2
そして、Vilは引きます!🎉🎉🎉ネストしたデータ構造をジェネリックパラメータとしてテストする場合
type NestedKeyRevert = TransformKeysToCamelCase<{
FOO_BAR: string
ANOTHER_FOO_BAR: true | number,
NESTED_KEY: {
NEST_FOO: string
NEST_BAR: boolean
},
}>
万事うまくいく.
あなたが最後までこの記事を読んだことを祝ってください.我々は、生のtypescriptでかなり先進的な仕事である入れ子状のキーケース変換をうまく付け加えました.
You can play with the full source code here
忘れないで🫀 この記事が好きなら.
Reference
この問題について(生のtypescriptジェネリックのキャメルケースへの方法), 我々は、より多くの情報をここで見つけました https://dev.to/svehla/typescript-transform-case-strings-450bテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol