{
    "componentChunkName": "component---src-templates-blog-post-jsx",
    "path": "/post/introduce-the-new-typescript-playground-for-advanced-use/",
    "result": {"data":{"site":{"siteMetadata":{"title":"WEB EGG","author":"Leko - CTO at Yuimedi"}},"markdownRemark":{"id":"2a7a2dc1-e643-59a7-8708-4383d6780be5","excerpt":"“外部ライブラリもインストール・型解釈できる TypeScript playground を作った”という題で俺得フロントエンド (1) LT 会という勉強会で登壇してきました。スライドはこちらです。 — 外部ライブラリもインストール・型解釈できる TypeScript playground…","html":"<p>“外部ライブラリもインストール・型解釈できる TypeScript playground を作った”という題で<a href=\"https://opt.connpass.com/event/130433/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">俺得フロントエンド (1) LT 会</a>という勉強会で登壇してきました。スライドはこちらです。</p>\n<blockquote>\n<p>— <a href=\"https://talks.leko.jp/advanced-typescript-playground/#0\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">外部ライブラリもインストール・型解釈できる TypeScript playground を作った</a></p>\n</blockquote>\n<p>スライドの内容をそのまま書いても意味がないので詳しくはスライドを読んでいただきたいのですが、発表時間の都合・構成力不足で伝えきれなかった部分の補足・補完的なものを書きます。<br>\nこの playground のより詳細な説明、内部で使ってる技術の説明、この playground に限らず汎用的に活用できそうな技術の話をします。</p>\n<!--more-->\n<h2 id=\"何を作ったの\" style=\"position:relative;\"><a href=\"#%E4%BD%95%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%9F%E3%81%AE\" aria-label=\"何を作ったの permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>何を作ったの</h2>\n<blockquote>\n<p>— <a href=\"https://playground.type-puzzle.org/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">TypeScript Playground | The unofficial playground for advanced TypeScript users</a></p>\n</blockquote>\n<p>↑ を作りました。</p>\n<h2 id=\"どうやって使うの\" style=\"position:relative;\"><a href=\"#%E3%81%A9%E3%81%86%E3%82%84%E3%81%A3%E3%81%A6%E4%BD%BF%E3%81%86%E3%81%AE\" aria-label=\"どうやって使うの permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>どうやって使うの</h2>\n<p>「動かないじゃん！」と言われても悲しいので、これをきちんと伝えておきたいです。<br>\nちゃんと使えるものにしたいので、何通りかのユースケース用にサンプルを共有し「なるほどこういうことができるのね」のイメージを掴んでいただきたいです。</p>\n<ul>\n<li><a href=\"https://playground.type-puzzle.org?c=H4sIAAAAAAAAA81TXU%2FbMBT9K5YlVJDaNCl0ZSkgPjS0PmxDW5%2B28GCc29bg2JZ9Q%2Bmq%2FPf5phQEmzRte9lD1Pj45Nxzjt01l7YEnnNVOeuRfQYhscvW7MJGwIBB1rCZtxUruKe9go8L80heMw%2BmBL%2BldFpGr7RVpzCFwZUDduWtC%2ByYrQvD2NwDoDLznAX08XdMIC48hIXVZc5MXd2Aj2gzJgGpRQjszDkGDxgnhWdXR63uyUY2oEAlWQkzUWtsd3J2JTwqobfERwcvxmUpQTSroXGbMLtHNHDr9Ljg70FrW3DWP%2Bmy0sq6iuOTOeA7DfR6vpqUux1vLXb29qIU73IM0pqZmvN8HeutnNLgPzlU1gSCbsNDLLztKpKNnVROK6nwzKx4jr6GLqd6JH6stb5YgLwLL%2FHL2khSm8aCX22dK1NeCK1jBv1KjYoAj6uJUVSM%2Bi5IY8t5tjFdqCdRCB9sWWuYGIT4%2BQZumi4vwVFbRipy8G3NjajoGp3SoYf%2BNlwswhHconF9Dz60Q3n2JtlPsn1OUkF65TZmOGX60q7pPBV5jbWxmfWbu0kfCCTNQZod9tKD3mA0TYf5%2Ftv8IEsOh8OvkaGVuWurNq6KzAVivBH9%2FnK5TCJyG5J4Kn0n5J2YQ3%2FnIG3t7QwuN7ZjPFffaBUW4EmkDuAf421zQCWUpnXoRcFeC59WSnob7AxJnlQiyWB8Yui2o78Uum66v%2ByX%2Fmi%2F6zhNhn9cMdt9kt%2F7ue4snWajfJjm6SAZZqN%2FrrtN8f9Vft38AGuDhuQbBQAA\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">@types/react, @types/react-dom で React の型推論</a></li>\n<li><a href=\"https://playground.type-puzzle.org?c=H4sIAAAAAAAAA41UTVPbMBD9Kzu6EKbgJP0axi0MlNKZdKa0A5xa96DYii2ir5FkQprmv3clO45NOTA5JNp97%2B1q9ykbkuuCkZRwabT1sIHcMurZrdeWwRYWVkvIiGVF%2FZiRD5nKlF8bBrceQXAKm0wB5LpWPgVVyzmziNlGXK6V88AV95yKiE%2BfpU2GhNn15c3Vt6vruxTrcoXtSKZ8RpA1OH%2FYET5f9QgFGxJ650FTbRQxo0M4PYPRBsK90n152B52JTqV%2F%2FFd9Qbfjuci9xyZCL9hvrbqDoMfQ0Yv9sXP4O8z6a7WWa%2FhMP%2Bc2VDeDSfZn%2B8R0Fg33dWPrcZZuxX3eQWjBpCEWodNBvdAHeuNvQkC1gytBUc0e4qFk3iAVzCFsLSOvl%2FCS%2BjHPXrBFrQW%2FikvwiNkO%2FSHi8487ft01I6nWcB4DDMPK22XLlMRnRTcGYr3H3WzHx0G8JNsN%2FomG6WurNU2hbAhOMhIpUuWkQPgDpT2QJ3jpaJzwcDr6IgA6rv279CEB8l%2FVXdO2ok3RiJHxDu88YKXJN3gK5WGC2a%2Fm7jYELp3j%2FhucQq5R7DSM2kEz7m%2FUGuSeluzI%2BK85bm%2FroW4rFi%2BdMP4l1pFN4S7PUl94qq4pEJcGCOeqP2w2jDr17PGePwPDRo7zL6Nu4q7ffQLivnK6rqsLtEvbqZuoyMbxHZ7hEMyTBVM5Tw082tDFJUsXhD%2FevCCOAwTzrWKvwoMPTDrYm3yNpkkUxJEXG65aToiP5CLHcf1RD%2BhF5WnXOFLWmgLX%2BkDvY14oMY45C%2FZGo1ThAa6wq25QgtBA7%2FNXhdPi3aMVOCBS1nvEpUOixH8gUUVI%2Bg6wEVUZUKS39hwUEzJ68n05Hg6OZ6%2BuZu8Td9M08m75P3rk5%2BRr5Zx38pIRFbeG5eOx6vVKsHIvcMnJceG5ktasvGu50pLZjDQEhAfMwnCtS2bdrTjaMR1T7PkvqrnUTDC710nOK9L9wLkmDtX4%2F5wn6aeC%2B4qHBz2Xjtm2316LgttwziZpFzsI%2Bftd1ANAphtl9X4oadB80LwuIqdRhs5l6ylD%2FAlZdRq1cMXVCV0bqnUD%2BdliD1He2Grv%2FHzD%2B4kKd1IBwAA\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Redux でシンプルなカウンター store の推論</a></li>\n<li><a href=\"https://playground.type-puzzle.org?c=H4sIAAAAAAAAA52SbWvbMBDHv4rQKCTgJI7XjNUlpVlLWaF0gwUGq%2FtCsZVYjZ6Q5HWZ8XffnZz0ae9KEsKd7v%2B70%2F3V0tJUnOZUKGtcIC1ZCxm4S4hilnRk7YwiBZWmYr4u6GmhCx12lpOvjWKazElbaEI0UzwnPjihN6eYYBuIdaNW3EHcRVlptA9EBK583svv7gFwh%2FXtHlHQG741BU16wvSEdMnr86VRT8dZ%2Bv8xc8%2FybEq6Qt%2B%2F7O4XVSMDtB20WEO6%2FShDMj%2BLibM5YF8oGNbfAt2DCHYyiBcY91sa7HnDBFrjCAUdnh6Uiu1WHK8DwmcKKHU1wFrsiP9jH5gL%2FqcI9QDuDwhk0IQGD6C12NC8BZeUFZK7bzYIoGPqwf8B3xxnZYBiba6VlaIUYaF3NA%2Bu4QlFR8pw20h5UfNy61%2FnrxpdIm0Jfr45%2BgJDXjApF9bKN7Tvzljuwu5aiyCYFH8ZMg41z2Msa7GHdl1CK265rrguBba6a%2BO2YPxzfEx%2B0r8vuAZc2WI%2BpiH%2BzZ2PeHo8nsL3Y0oR5ksnbN%2BX4vg%2FYkwqDtsVcUNkbRy5MaPLnluxgNgsnZ6M0tkoS5fTT3k6y2fZ%2BHM2%2BwUVUuht3Ku2CirrEKzPJ5PHx8cxZB78GCyYWFZu4ZVMjo7TOOFRdvU0em0Ut3D4QrwBT5tVVF72o3G5w3mrt%2FEH8LGCjSRgqDVeBON27wIBYdVs%2FLu0E%2BF9A2sHv2yzksLX3OFGGs%2Fd3q%2BDL1wxITH2I9jOKKbPlSid8WYdsBlSoEgH%2BIGJ0fR3gu7h8w9nd7wjqQQAAA%3D%3D\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Lodash でなんのアテもなくただ推論させる</a></li>\n<li><a href=\"https://playground.type-puzzle.org?c=H4sIAAAAAAAAA51TXW%2FbMAz8K4KQAg7gOF8dtmXo0K5Dge6hGdA%2BbemDKjO2WlnSJHmJE%2FS%2Fj7STGO3jYMSIyOPdkZT3XNoc%2BIIPkmTILr6y%2FcowJq0JkQ28tZFdsEGy4s7Dig8px1gmQ8DQk5Avhbe1yUfSautXPGUr7iHvgbmIApGlLaDLCiH6rHAOTJ50J9bK9NkOEaOneg%2Frrr6M0YXFeOy0aDrtLDYORq7e7TRk1hdvCSJsIxIsUYj1NSfM8MvK0L9BVkD8cb%2B8S3oJ2IrKIae0VW85lmAS6opG1c6nk6DaLESvTKHWTYtImam1TtlsODzNTURZJkC1NGGL7OC99QmcIEJvRBMOuziCtC3Q2HdraAfk%2BZVePOUxIGStCr7Y4x4rpzT4pYsK6yj0HLa4WQ9CRgQbe4sNKanilWn4IvoaUk6eZbxDp9clyJfwNn5TG0lsDzjjd6lvyuTXQusr5%2FQ7tp%2FeOvCxuTUqKqHVThDHEdPbeCjViTR2Cr%2F5858afMMfX19TngNdEDBStbk9N6Kiu3rZoscHKMpKFMR4R5Lyv%2BBDq8jn2TybcmIK0ivX%2BeDUzn17ZjmsFdnEibG19ezEiSskytlk%2Bmk0mY8mnx8mk8X5dDGfZR8%2Bnv9ChFbmpR2zcRUij%2Fdms9lkGHkOdHPGDj8SUcD47HzSujub3RwksD9XP2kVSvDEUgfwh%2F6OfUAllKZzGCHjqA1fVkp6G%2Bw6Ej%2BxIMhE%2FGHT7ZD%2Bk%2BgRn3%2F3SSgwDgQAAA%3D%3D\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">jQuery などのグローバル変数が生えるパターン</a>\n<ul>\n<li>tsconfig.json に<code>types</code>フィールドを足しています</li>\n</ul>\n</li>\n<li><a href=\"https://playground.type-puzzle.org?c=H4sIAAAAAAAAA51T70%2FbMBD9V06WkFKpTZNStJHBxI8Jxj5sk8anrUgE99oYHNuynRZW%2Br%2Fv7JAW2PgytbWb83vv7p4vK8b1FFnBuCydg3OL6IWaw2qiALhWztuGe20TY8Wi9Ail%2B0RbAWHtwWo9UQE5R99Rk14BxNqIPMlABYfgK%2BHSViElymfdWJf0PrQwMYOkggPYg8dHyN%2FBwSFUvU4DwKJvrIIJO9d6CrhARSkm7Im8BpQONxp5%2Fiaz1vZfzDfQ5cyjVVqrLT5stMTOp%2Bi4FTeYEPyp%2FwnrQ9KDw4%2Bt5DPEM5Negah5T4A2tYPr54Vew7JCBXtFlv3F6rxVeknuKlzGa9k4CuEgdZ3Re33I2u8W0PLn3bW3IpurJPoWivcGuU86bPriznup1yfRhhced%2Bx1%2ByducWF95h0ln4k5K1Y0hLUREu034wVVFEK37p7G0mLJPYGVvqiNFFz4Y%2FXACppK7LMwZtx%2FbaQ8rZDfuZfxs0bxoHb5YPDV0YlQ09NSymNj5Cu171YbtP7hQgkvSil%2Bl0Gjw2zLuKRR7qK%2BzfCL3aLz7Gq97rMpGqTpUFzEkxVTZR1es6OIHUYgpeSUjKKtQJ8t0LqYjY1G6SjdZUEozI9pi2Chlx%2FxmQZrJkKNZBfMtIUvreSUBiDws%2Fz9IBsP8vwy3y%2Fy3SIbp9n%2B%2BCchpFB30WFlakJW3htXDIfL5TKlyK1L6TKGpuR35RyHO%2BMsFrczOos1U2umuZHCVWiDRuPo9Whb65rAuhQyPLsB6Q1i%2BKgW3GqnZz6oBxUCKU8%2F6jj6859CV%2FT5Ax4Dj87EBAAA\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">jest のアサーション周り</a>\n<ul>\n<li>tsconfig.json に<code>types</code>フィールドを足しています（jest に型ゲーなんてあるのか？ という感じですが色々あるアサーションメソッドの補完が効きます）</li>\n</ul>\n</li>\n<li><a href=\"https://playground.type-puzzle.org?c=H4sIAAAAAAAAA51SbW%2FTMBD%2BK5b5MlCbtgxGyTTBmIQ0CcHEyhfIPrjJtfHq2J7PXglV%2Fztnpy1tJYSGqqrXx8%2BL73wrXpoKeM5lY43z7AUTyB6QzZxpWMEfAri2j95JPS%2F4eaELXRqNnlnhECp2Qdws1ScFf5fYF7WZQ8Gfn2%2BpCe2YnZGctSerDs4po%2BOzdVTwHvdIspmc83xFd2usVOC%2BWC%2FJK0L3%2BJNu60CUnsjaXDdWyVL6S93y3LsAPR5TSv85KHVVQ7nAQ%2Fxj0GV0m7QWjo4%2BSF1dCaUurVVHbjfOWHC%2BvdbSS6HkLxE9tpw%2F15jUcmO6Xvd4BRZ0BbqUMerHimvRxGHvj5W6oI5thINOVUXQIzhMAfwse5MNefTC0knbxfKbOHMmdMV2M2Xfvn7aDLvDkFQLaJfGVTGdT51ZIjhCE2sXn%2F7xrtMOiEp6VdFsf8EnXXCqQxB2fEqmmnqMexSvuSkQhCvrpEZ%2BRwfCxx5fDkdv%2B8Oz%2FnA8GQ3zV%2BP89HV2Ohp%2FJ4WSepHeWNuGmLX3FvPBYLlcZoTcY0brMLCiXIg5DI5GWJsGLOF7urn0dZgmEdLDOkDj6oAHyme0SFUTr%2BvAGpTe0CSeZkHaaaBZP001kIiBloKWRARfG5f67rbjNonYbVLF2TZCKsL3zd7PIxgzNs9yeLw9oOfemO6fxlQbpkpiDSn4b7x%2FZpMR1drTlxY2rfj%2Fe93R5zeloGfZkAQAAA%3D%3D\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">query-string を適当に使う</a>\n<ul>\n<li>@types ではなくパッケージ自体に型定義ファイルが含まれている例です</li>\n</ul>\n</li>\n</ul>\n<p>デモをいくつか見ると気づくかもしれませんが、<code>react</code>のように型定義のないパッケージはインストール不要で、代わりに<code>@types/react</code>のインストールが必要です。react は型定義を配布していないため、@types のパッケージが必要になります。<br>\n一方でパッケージ自体が型定義を配布している query-string や Redux などのパッケージはそれ自体を入れる必要が有ります。</p>\n<p>文字にするとややこしいんですが、「普通に開発するときにインストールすること」と同じように使えば動くはずです。</p>\n<h2 id=\"なんで作ったの\" style=\"position:relative;\"><a href=\"#%E3%81%AA%E3%82%93%E3%81%A7%E4%BD%9C%E3%81%A3%E3%81%9F%E3%81%AE\" aria-label=\"なんで作ったの permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>なんで作ったの</h2>\n<p>TypeScript の playground といえば、<a href=\"https://www.typescriptlang.org/play/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">TypeScript 公式の playground</a>がまっさきに思い浮かぶと思います。主な機能は以下のとおりです。</p>\n<ul>\n<li>１ファイルで完結するくらいの TypeScript の型チェック</li>\n<li>TypeScript のコードを書いて、JavaScript にトランスパイル</li>\n<li>トランスパイルされた JavaScript を実行して動作確認</li>\n<li>tsconfig の一部オプションをトグル可能</li>\n<li>書いたコードを復元できる URL を生成し共有</li>\n</ul>\n<p>“〜をする Conditional Type”みたいな、ちょっとしたクイズとしては十分に活用できますし、TypeScript のようなトランスパイル文化に親しみのない方が具体的にどのような JavaScript が生成されるのかを理解したり、実行して成功体験を少しずつ積んだりと、ひとまず TypeScript に触ってみるものとしてとてもいい作りだと思っています。</p>\n<p>ただ、型にフォーカスしたときにやや物足りないと思うことがあります。具体的には以下の問題が挙げられます。</p>\n<ul>\n<li>型定義を提供している npm パッケージと絡めた型が書けない</li>\n<li>tsconfig でいじれる項目に限りがある</li>\n<li>JSX が使えない</li>\n<li>使ってる TypeScript のバージョンがわからない</li>\n</ul>\n<p>対象ユーザと存在意義が違うので、中途半端に本家に混ぜてどっちつかずになるよりも、とことん自分がほしいものを追求した playground を作ってみよう（その後は実用レベルになってから考えよう）と思いたち制作に至りました。</p>\n<h2 id=\"技術的なところ\" style=\"position:relative;\"><a href=\"#%E6%8A%80%E8%A1%93%E7%9A%84%E3%81%AA%E3%81%A8%E3%81%93%E3%82%8D\" aria-label=\"技術的なところ permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>技術的なところ</h2>\n<p>だいたいはスライドの方に書いたので、書き足りないところ・省略したことについて加筆します。</p>\n<ul>\n<li>monaco-editor の API の調べ方</li>\n<li>ブラウザで文字列の圧縮・解凍</li>\n<li>ブラウザでコードフォーマット（prettier）</li>\n<li>comlink-loader での WebWorker 化がすごい</li>\n</ul>\n<h2 id=\"monaco-editor-の-api-の調べ方\" style=\"position:relative;\"><a href=\"#monaco-editor-%E3%81%AE-api-%E3%81%AE%E8%AA%BF%E3%81%B9%E6%96%B9\" aria-label=\"monaco editor の api の調べ方 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>monaco-editor の API の調べ方</h2>\n<p>トーク後に「monaco で〜をするにはどんな API・機能を利用すればいいのか、ドキュメントを見てもいまいちわからない」という話をもらったので補足しますが、特別なことはありません。<br>\nAPI ドキュメントを隅から隅まで読む、目的から Issue を探してコメントを追う、ソースコード読むなどして泥臭く可能性を探り、monaco 公式の playground にて実験して確証を得てます。</p>\n<p>公式ドキュメントはこちらです。</p>\n<blockquote>\n<p>— <a href=\"https://microsoft.github.io/monaco-editor/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Monaco Editor</a></p>\n</blockquote>\n<p>公式 playground はこちらです。<br>\nユースケースごとに boilerplate が用意されており、初期コードを書き換えてだんだん挙動を理解していく形になると思います。<br>\nなお monaco-editor の playground にはシェア機能がありません。付け足したい。</p>\n<blockquote>\n<p>— <a href=\"https://microsoft.github.io/monaco-editor/playground.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Monaco Editor Playground</a></p>\n</blockquote>\n<p>TypeScript に絞って理解を深めるとっかかりを紹介すると、</p>\n<ul>\n<li>TypeScript の Language Service、Compiler API が前提知識として必要です\n<ul>\n<li>API が確定していないため、これらの情報もドキュメントがありません。公式の Wiki や handbook を手がかりに手探りしましょう</li>\n<li><a href=\"https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Using the Compiler API · microsoft/TypeScript Wiki</a></li>\n<li><a href=\"https://github.com/Microsoft/TypeScript/wiki/Using-the-Language-Service-API\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Using the Language Service API · microsoft/TypeScript Wiki</a></li>\n<li><a href=\"https://basarat.gitbooks.io/typescript/docs/compiler/overview.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">TypeScript Compiler Internals · TypeScript Deep Dive</a></li>\n</ul>\n</li>\n<li><a href=\"https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.typescript.languageservicedefaults.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\"><code>monaco.languages.typescript.LanguageServiceDefaults</code></a>に TypeScript の LanguageService を操作するための API が生えています\n<ul>\n<li><code>setCompilerOptions</code>メソッドで tsconfig.json を読み込ませられます\n<ul>\n<li>エディタに書かれた tsconfig.json（文字列）から<code>CompilerOptions</code>を得るに Compiler API のメソッドを理解する必要があります</li>\n<li>JSON.parse だとコメントがパースできないので TS API を使うのが楽</li>\n</ul>\n</li>\n<li><code>addExtraLib</code>メソッドで「このファルパスにこういう型定義ファイルがある（ことにする）」を LanguageService に通知できます</li>\n</ul>\n</li>\n</ul>\n<blockquote>\n<p>— <a href=\"https://stackoverflow.com/questions/43058191/how-to-use-addextralib-in-monaco-with-an-external-type-definition\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">How to use addExtraLib in Monaco with an external type definition - Stack Overflow</a></p>\n</blockquote>\n<h2 id=\"ブラウザで文字列の圧縮解凍\" style=\"position:relative;\"><a href=\"#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7%E6%96%87%E5%AD%97%E5%88%97%E3%81%AE%E5%9C%A7%E7%B8%AE%E8%A7%A3%E5%87%8D\" aria-label=\"ブラウザで文字列の圧縮解凍 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>ブラウザで文字列の圧縮・解凍</h2>\n<p>公式 playground と同じく、クエリパラメータにアプリの状態（コードや tsconfig、依存パッケージとそのバージョン etc）をすべて載せて共有できるようにし、ページロード時にクエリパラメータから状態を復元する方式を取りました。<br>\nよほど長いコードを書かない限りは愚直に base64 エンコードするだけで十分なのですが、共有可能なデータ量を増やすためにブラウザだけで完結する圧縮・解凍を実現する<a href=\"https://www.npmjs.com/package/pako\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">pako</a>にたどり着きました。</p>\n<p>API の互換性はありませんが、Node.js の<a href=\"https://nodejs.org/api/zlib.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">zlib</a>モジュールのような感覚で使用できます。<br>\nBrotli には対応してなかったため gzip を使用したところ、本アプリにおける圧縮率はだいたい 30％でした。無圧縮よりも 30％ほど多くのデータ（コード）をシェアできるようになります。</p>\n<p>実際のコードはこのあたりです。<br>\n<a href=\"https://github.com/Leko/type-puzzle/blob/61097601b7b35f92b3f611e164731496ffe1d601/packages/playground/src/lib/share.ts\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://github.com/Leko/type-puzzle/blob/61097601b7b35f92b3f611e164731496ffe1d601/packages/playground/src/lib/share.ts</a></p>\n<blockquote>\n<p>WebAssembly に port された Brotli 実装の<a href=\"https://github.com/dfrankland/wasm-brotli\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">wasm-brotli</a>というモジュールも試してみました。圧縮率は 40％と高かったのですが、gzip でも十分用途に足りていると判断し、利用ユーザ数が多い pako を採用しました。</p>\n</blockquote>\n<h2 id=\"ブラウザでコードフォーマットprettier\" style=\"position:relative;\"><a href=\"#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7%E3%82%B3%E3%83%BC%E3%83%89%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88prettier\" aria-label=\"ブラウザでコードフォーマットprettier permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>ブラウザでコードフォーマット（prettier）</h2>\n<p>prettier をブラウザで使うのは非常に簡単で、ドキュメントのとおり書くだけです。</p>\n<blockquote>\n<p>— <a href=\"https://prettier.io/docs/en/browser.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Browser · Prettier</a></p>\n</blockquote>\n<p>WebWorker のサンプルコードも紹介されておりいたれりつくせりなんですが、Off the main thread を実現するにあたって、素の WebWorker のコードを書くよりも、webpack の<a href=\"https://github.com/webpack-contrib/worker-loader\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">worker-loader</a>を使うよりも、<a href=\"https://github.com/GoogleChromeLabs/comlink\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Comlink</a>を経由して暗黙的に WebWorker を利用するよりも、全力で振り切って<a href=\"https://github.com/GoogleChromeLabs/comlink-loader\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">comlink-loader</a>を使うアプローチが面白かったので紹介します。</p>\n<h2 id=\"comlink-loader-での-webworker-化がすごい\" style=\"position:relative;\"><a href=\"#comlink-loader-%E3%81%A7%E3%81%AE-webworker-%E5%8C%96%E3%81%8C%E3%81%99%E3%81%94%E3%81%84\" aria-label=\"comlink loader での webworker 化がすごい permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>comlink-loader での WebWorker 化がすごい</h2>\n<p>もはや黒魔術の域を超え闇の魔術ではないか？ とすら思うのですが、GoogleChromeLabs が開発している<a href=\"https://github.com/GoogleChromeLabs/comlink-loader\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">comlink-loader</a>という Webpack loader があります。<br>\nComlink を生で使っている間は WebWorker の存在を利用者が認識しないといけないのですが、comlink-loader によって <strong>WebWorker の存在がコードからほとんど消失します。</strong></p>\n<p>重たい処理の例として、こんなクラスがあったとします。<br>\n無駄にループを回してメインスレッドを固めます。引数と戻り値を適当に付けておきました。<br>\nこの重い処理が例えば圧縮・解凍アルゴリズムだったり、prettier だったりするという前提で適宜重たそうな処理に読み替えてください。</p>\n<div class=\"gatsby-highlight\" data-language=\"ts\"><pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">SomeHeavyTask</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">async</span> <span class=\"token function\">run</span><span class=\"token punctuation\">(</span>loopCount<span class=\"token operator\">:</span> <span class=\"token builtin\">number</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> startsAt <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">let</span> i <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">&lt;</span> loopCount<span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getTime</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> startsAt<span class=\"token punctuation\">.</span><span class=\"token function\">getTime</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>この<code>SomeHeavyTask</code>はこのように使います</p>\n<div class=\"gatsby-highlight\" data-language=\"ts\"><pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> SomeHeavyTask <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./some-heavy-task'</span>\n\n<span class=\"token keyword\">const</span> task <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">SomeHeavyTask</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\ntask<span class=\"token punctuation\">.</span><span class=\"token function\">run</span><span class=\"token punctuation\">(</span><span class=\"token number\">1_000_000_000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>spent <span class=\"token operator\">=></span> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">spent: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>spent<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">ms</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>この処理を comlink-loader に書き換えるとこうなります。</p>\n<div class=\"gatsby-highlight\" data-language=\"ts\"><pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"token keyword\">import</span> SomeHeavyTask <span class=\"token keyword\">from</span> <span class=\"token string\">'comlink-loader!./some-heavy-task'</span>\n\n<span class=\"token keyword\">new</span> <span class=\"token class-name\">SomeHeavyTask</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>task <span class=\"token operator\">=></span> task<span class=\"token punctuation\">.</span><span class=\"token function\">run</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span>spent <span class=\"token operator\">=></span> <span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">spent: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>spent<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">ms</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<ul>\n<li>コンストラクタが <code>Promise&#x3C;SomeHeavyTask></code> にかわる</li>\n<li>WebWorker に渡せる値しか渡せない</li>\n<li>WebWorker でできることしかできない（ex. DOM 操作はできない）</li>\n</ul>\n<p>という制約はあり、挙動を理解してないとむしろハマりそうな気もしますが、かなり低コストで Off the main thread が実現できるので、カジュアルに重たい処理は worker に逃がすって戦略を取りやすくなります。<br>\n処理が Worker に分けた結果 Code splitting も効くので、「特定用途にしか使ってない、ファイルサイズ的にも処理内容的にもヘビーなライブラリ」は格好の移行対象です。</p>\n<p>\n<div class=\"gprgh-container\">\n  <div class=\"gprgh-filename-container\">\n    <a class=\"gprgh-filename\" href=\"https://github.com/Leko/type-puzzle/blob/61097601b7b35f92b3f611e164731496ffe1d601/packages/playground/src/playground.tsx#L15\">type-puzzle/packages/playground/src/playground.tsx</a>\n  </div>\n  <span class=\"gprgh-meta\">\n    Lines 15 in <a class=\"gprgh-meta-sha\" href=\"https://github.com/Leko/type-puzzle/commit/61097601b7b35f92b3f611e164731496ffe1d601\">6109760</a>\n  </span>\n</div>\n\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber 14\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> ShareWorker <span class=\"token keyword\">from</span> <span class=\"token string\">\"comlink-loader!./lib/share\"</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div></p>\n<p>\n<div class=\"gprgh-container\">\n  <div class=\"gprgh-filename-container\">\n    <a class=\"gprgh-filename\" href=\"https://github.com/Leko/type-puzzle/blob/61097601b7b35f92b3f611e164731496ffe1d601/packages/playground/src/playground.tsx#L17\">type-puzzle/packages/playground/src/playground.tsx</a>\n  </div>\n  <span class=\"gprgh-meta\">\n    Lines 17 in <a class=\"gprgh-meta-sha\" href=\"https://github.com/Leko/type-puzzle/commit/61097601b7b35f92b3f611e164731496ffe1d601\">6109760</a>\n  </span>\n</div>\n\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber 16\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">import</span> PrettierWorker <span class=\"token keyword\">from</span> <span class=\"token string\">\"comlink-loader!./lib/prettier\"</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div></p>\n<p>余計なテンプレート、グルーコードを増やさず気軽に Off the main thread を推し進められる強い武器（諸刃かもしれない）でした。</p>\n<h2 id=\"さいごに\" style=\"position:relative;\"><a href=\"#%E3%81%95%E3%81%84%E3%81%94%E3%81%AB\" aria-label=\"さいごに permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>さいごに</h2>\n<p>スライドにも書いてあるのですが、完成度を上げて本家 playgrond に還元したいと思っています。<br>\n私一人のユースケースでは品質的にもコンセプト的にも甘いと思うので、ぜひ使ってみてフィードバックをいただけると幸いです。</p>","timeToRead":23,"frontmatter":{"title":"「外部パッケージの型定義もインストールし推論できるTypeScript playgroundを作った」という題で登壇してきました＋スライドの補足","tags":["TypeScript","JavaScript","npm","WebWorker","comlink"],"date":"June 13, 2019","featuredImage":{"childImageSharp":{"fluid":{"tracedSVG":"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='400'%20height='200'%20viewBox='0%200%20400%20200'%20preserveAspectRatio='none'%3e%3cpath%20d='M372%206l-1%205v4h21V5h-10l-10%201M69%20112v77h331v-77a1838%201838%200%2000-3-75h-1l-163-1H69v76M3%2072l1%205h62V67H3v5'%20fill='%23d3d3d3'%20fill-rule='evenodd'/%3e%3c/svg%3e","aspectRatio":2,"src":"/static/1bb6f00560555da248c7687d79a6c688/8eab8/featured-image.png","srcSet":"/static/1bb6f00560555da248c7687d79a6c688/1ec58/featured-image.png 334w,\n/static/1bb6f00560555da248c7687d79a6c688/ccb4a/featured-image.png 668w,\n/static/1bb6f00560555da248c7687d79a6c688/8eab8/featured-image.png 1336w,\n/static/1bb6f00560555da248c7687d79a6c688/85e22/featured-image.png 2004w,\n/static/1bb6f00560555da248c7687d79a6c688/22f13/featured-image.png 2048w","srcWebp":"/static/1bb6f00560555da248c7687d79a6c688/f7e47/featured-image.webp","srcSetWebp":"/static/1bb6f00560555da248c7687d79a6c688/cd98f/featured-image.webp 334w,\n/static/1bb6f00560555da248c7687d79a6c688/7535d/featured-image.webp 668w,\n/static/1bb6f00560555da248c7687d79a6c688/f7e47/featured-image.webp 1336w,\n/static/1bb6f00560555da248c7687d79a6c688/f6b67/featured-image.webp 2004w,\n/static/1bb6f00560555da248c7687d79a6c688/96ec1/featured-image.webp 2048w","sizes":"(max-width: 1336px) 100vw, 1336px"}}}}}},"pageContext":{"slug":"/introduce-the-new-typescript-playground-for-advanced-use/","previous":{"fields":{"slug":"/jsconfeu2019/"},"frontmatter":{"title":"JSConf EU 2019に行ってきました","tags":["JavaScript","JSConf","Community"]}},"next":{"fields":{"slug":"/deno-ja-on-techbookfest-7/"},"frontmatter":{"title":"技術書典に初参加しdenobook 02を執筆・頒布しました＆電子版のご案内","tags":["JavaScript","TypeScript","Rust","Deno"]}}}},
    "staticQueryHashes": ["2585454260","2954598359"]}