LoginSignup
215
144

More than 3 years have passed since last update.

TypeScript 4.1 の Template Literal Types がやばい

Last updated at Posted at 2020-09-29

TS 4.1 の Template Literal Types を使うと、文字列を解釈して型定義ができる。文字列は変数化でき、テンプレートリテラルで埋め込める。

type Hello = 'Hello'
type World = 'World'

// Template Literal を埋め込める
type HelloWorld = `${Hello}, ${World}`
// => type 'Hello, World'

// 引数に取ることもできる
type Concat<T extends string, S extends string> = `${T}, ${S}`
type HelloWorld = Concat<'Hello', 'World'> 
// => type 'Hello, World'

やばい。革命的だ。

更にやばいのが、 infer を使って任意の文字列にマッチ、みたいなことができる!

type GetWorld<T extends string> = T extends `Hello, ${infer World}` ? World : never
type World = GetWorld<`Hello, World`>
// => type 'World'

infer は一つのリテラルで複数回使えるので、簡単な SQL くらいならすぐパースできる。以下は型レベルでSQLがパースできる例。

image.png

infer と再帰的な型定義を使えば、ツリー構造を型レベルでパースしたり、文字列を分割することも可能。(後で例を書きます)

既に SQL から型定義を作成したり、 GraphQL の Resolver の型定義をするライブラリが作成されつつある。

2年前、 typed-graphqlify という OSS を作ったが、Template Literal Types を使えば、もっとすごいものが作れる。

試しに GraphQL から型定義を自動作成するものを、ちょっと書いてみた。

/*
 * TypeScript 4.1
 */

type GetSchema<Schema> =
  Schema extends `type Query { ${infer RootQueryName}: String! }`
    ? { [k in RootQueryName]: string }
    : never

type QueryBuilder<Schema, Query> = Query extends `{ ${infer RootQueryName} }`
  ? RootQueryName extends keyof Schema ? { [k in RootQueryName]: Schema[RootQueryName] } : never
  : never

type Schema = GetSchema<`type Query { hello: String! }`>

type ExpectQueryType = QueryBuilder<Schema, '{ hello }'> // => { hello: string }
type ExpectNever = QueryBuilder<Schema, '{ foo }'> // => never

見た目はえげつないけど、ちゃんと動いている。がんばればライブラリ化できるかもしれない。 typed-graphqlify の次期バージョンとして作ろう。

ただ、 Fragment とか面倒そうw
頑張る。

[追記]
実装のヒントを貰うために、 graphql-typed-ast に Issue を立てた。良い人だ。
https://github.com/dotansimha/graphql-typed-ast/issues/2
[/追記]

215
144
3

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
215
144