よく使いそうなtemplate-literal-typesを使った型定義
いつもTSのPlaygroundで作ってるなぁと思うやつをメモする
下に書いてあるやつすべてplaygroundで実行しているやつ
splitの型定義
// 文字列を受け取って受け取ってその文字列をDelimiterでsplitする型 type Split<T, U extends string> = T extends string ? T extends "" ? [] : T extends `${infer Head}${U}${infer Tail}` ? [Head, ...Split<Tail, U>] : [T] : [] type UseSplit1 = Split<"aaaaaa", ""> // 1文字づつ区切る type UseSplit2 = Split<"abababab", "b"> // 特定文字で区切る type UseSplit3 = Split<"a,b,c", ","> // csv的なやつ
nestしたobjectのkeyを列挙する型定義
// nestしたオブジェクトのkeyをすべて列挙する型 // json to csv的なやつに使えそうかも type NestObjectKeys<T, D extends string = "."> = { [K in keyof T]: K extends string ? T[K] extends Record<string, unknown> ? `${K}${D}${NestObjectKeys<T[K], D>}` : K : never }[keyof T] const obj1 = { a: 1, b: null, c: "c", d: { a: 1, b: undefined, c: "dc", d: { a: 2, b: null, c: "ddc" } } } as const type Keys1 = NestObjectKeys<typeof obj1> // objectのkeyを.でつなげる type Keys2 = NestObjectKeys<typeof obj1, "-"> // 特定の文字でつなげる
よくあるrouterライブラリのpath文字列を型に落とし込む型定義
// あるあるのrouterライブラリのpath文字列を型に落とし込む型 type AnalyzePath<T> = T extends string ? T extends `/${infer Head}/${infer Tail}` ? Head extends `:${infer U}` ? { [K in U]: string } & AnalyzePath<`/${Tail}`> : AnalyzePath<`/${Tail}`> : T extends `/:${infer U}` ? { [K in U]: string } : {} : {} type AnalizedPath1 = AnalyzePath<"/users/:user_id/"> type AnalizedPath2 = AnalyzePath<"/users/:user_id/tweets/:tweet_id">
Nextjsのpath文字列を型に落とし込む型
これ型に落とし込めてもnextjsはfsでroutingされているからあまり意味ないんだよなぁと言うのが最近の悩み。ずっと考えてるけどいい方法思いつかないなぁ.....next.config.js
にwithXXX
でコンパイラをいじったりしていい感じにするとかかなぁ....わかりません
// Nextjsのpath文字列を型に落とし込む型 type AnalizeNextJSPath<T> = T extends string ? T extends `${infer Head}[${infer U}]${infer Tail}` ? U extends `...${infer U1}` ? { [K in U1]: string[] } & AnalizeNextJSPath<Tail> : { [K in U]: string } & AnalizeNextJSPath<Tail> : {} : {} type AnalizedNextJSPath1 = AnalizeNextJSPath<"/users/[id]/"> type AnalizedNextJSPath2 = AnalizeNextJSPath<"/users/[id]/directory/[...directories]/">
snake caseをcamel caseにする型
// snake case to camel case type SnakeToCamel<T> = T extends string ? T extends `${infer Head}_${infer Tail}` ? `${Lowercase<Head>}${Capitalize<Tail>}` : never : never type UseSnakeToCamel = SnakeToCamel<"user_id" | "tweet_id">
camel caseをsnake caseにする型
// camel case to snake case type CamelToSnake<T> = T extends string ? T extends `${infer Head}${infer Tail}` ? Head extends Uppercase<Head> ? `_${Lowercase<Head>}${CamelToSnake<Tail>}` : `${Head}${CamelToSnake<Tail>}` : T : never type UsecCamelToSnake = CamelToSnake<"userId" | "tweetId">
まとめ
便利ですね。template-literal-types。一生遊べる