タグ

ブックマーク / susisu.hatenablog.com (24)

  • TypeScript の DI 手法あれこれ - Object.create(null)

    TypeScript で DI (依存性注入) するためのライブラリを作ったんですが, それを紹介する前に既存手法をまとめておいた方が説明が楽だなと思ったのでまとめておきます. そもそも DI の目的とは, みたいなところは詳しく説明しないのであしからず. 手法の比較 DI なし Service Locator エフェクト Constructor Injection Setter Injection デコレータ typed-inject 次回予告 手法の比較 DI なし まずは DI を使わない場合を見ていきましょう. ここでは例として, 以下のような時刻と乱数を必要とするコンポーネント MyService が, 時刻と乱数を扱う機能をそれぞれ提供するコンポーネント Clock と Random に依存するような場合を考えます. type Clock = { getTime: () =>

    TypeScript の DI 手法あれこれ - Object.create(null)
  • 中止ボタンがしいたけに見えて困る - Object.create(null)

    令和最新版. Vivaldi でアイコンがカスタマイズできるようになっている テーマ設定画面を眺めていたら, Vivaldi 6.0 からツールバーのアイコンがカスタマイズできるようになっているのに気がつきました. 流石 Vivaldi です (?) vivaldi.com しいたけ復活 こうなっては中止ボタンをしいたけにするしかありません. しいたけアイコンは以下で用意されていたものを拝借します*1. バッテン髪飾り派の人も安心. momizine.hatenadiary.org というわけで完成です. フラットデザイン全盛の時代にスキュモーフィックしいたけが悪目立ちしていて最悪ですね. *1:画像の究極の出典ではないかもしれないので, そのあたりの扱いは自己責任で

    中止ボタンがしいたけに見えて困る - Object.create(null)
  • 共通化すれば良いとは限らない - Object.create(null)

    ここのところ偶然なのか「共通化」という言葉を多く聞いているのですが, その言葉を聞くたびに身構えていることに気がついたので, この気持ちの出どころを共有しておきます. なぜ身構えているかというと, 共通化が必ずしもコードを良い状態にするとは限らないにも関わらず, それ自体が目的になってしまっている (ように見える) ことが多いからです. この手のリファクタリングの目的はあくまでコードの改善のはずで, そのことを忘れて共通化するだけで満足してしまうと, 良くてリファクタリングの効果が半減, 悪ければ逆効果になってしまいます. 個人的にコードを共通化する上で注意してほしいと思っているのは以下の二つです. コードを共通化すべきでない場合もある 共通化されたコードは一般的な原則にしたがって設計されなければならない 似たようなことは歴史の中で何度も繰り返し言われていることだろうと思いますが, 改めて

    共通化すれば良いとは限らない - Object.create(null)
  • TypeScript 型レベルプログラミング フリースタイルガイド - Object.create(null)

    TypeScript の型レベルプログラミングのための真面目なスタイルガイドではありません. 型なしラムダ計算で喜ぶような人間が使うための諸刃の剣です. この記事の内容は TypeScript2022 年 1 月時点での最新版である 4.5.4 に基づいています. 将来のバージョンでの妥当性は保証しません. 「型〜」「〜型」という用語の「型」はしばしば省略します. 値レベルの話題は一切登場しません. 以前作った型レベル Brainfuck インタプリタはこのスタイルに則っているので参考にどうぞ. いつまでこのネタを引きずるんですか? パラメータに対して制約を付与しない 型定義のパラメータに対して extends を使って制約を付与すると, そのパラメータに与えられる引数を制約を満たすもののみに限定することができます. 例として, 以下の Append には string の部分型のみ

    TypeScript 型レベルプログラミング フリースタイルガイド - Object.create(null)
  • CloudWatch Logs Insights を使って Mackerel 上にアプリケーションのメトリック監視環境を手早く構築する - Object.create(null)

    この記事は Mackerel Advent Calendar 2021 の 15 日目の記事です. 昨日は id:kazeburo さんの mkr plugin install 時の403 API rate limit exceededエラーを回避する方法 でした. こんにちは id:susisu です. 普段は Mackerel 開発チームでアプリケーションエンジニアをしています. 先日 mackerelio-labs にて cloudwatch-logs-aggregator という Terraform モジュールをひっそりと公開しました. github.com この記事では, このモジュールについてと, これを使って AWS 環境で動作するアプリケーションのメトリックの監視環境を手早く Mackerel 上に構築する方法を紹介します. アプリケーションのメトリックについて (ここでア

    CloudWatch Logs Insights を使って Mackerel 上にアプリケーションのメトリック監視環境を手早く構築する - Object.create(null)
  • TypeScript をより安全に使うために まとめ - Object.create(null)

    こういう一連の記事を書きました. susisu.hatenablog.com susisu.hatenablog.com susisu.hatenablog.com TypeScript の型安全性 TypeScript の型システムは健全ではありません. TypeScript Design Goals にある通り, そもそも言語設計の段階で完璧な型安全性は目標になっておらず, 既存の JavaScript の言語仕様や資産を活用しやすいように, 生産性や利便性とのバランスをとることを目標としています. では TypeScript の型システムではどの程度の安全性が保証されるのでしょうか? 型安全性を第一の目標に置いていないとはいえ, TypeScript がまったく見当違いな型検査をしているというわけではありません. したがって, ある制限された範囲内であれば, 安全性を担保するのに十分

    TypeScript をより安全に使うために まとめ - Object.create(null)
  • TypeScript をより安全に使うために その 2: オブジェクトの具体的な形にアクセスするのを避ける - Object.create(null)

    前回はこちら. susisu.hatenablog.com 引き続き環境は以下を前提とします: TypeScript 4.4 (この記事を書いている 2021 年 11 月時点の最新版) strict: true 原則: オブジェクトの具体的な形にアクセスするのを避ける 具体例 in 演算子による型の絞り込み Object.keys の誤った使用 Object.values, Object.entries の使用 リテラルの先頭以外での object sperad 次回 原則: オブジェクトの具体的な形にアクセスするのを避ける ここで「オブジェクトの具体的な形にアクセスする」とは, 静的な型によらずに, 実行時にオブジェクトがどのようなプロパティを持っているかといった情報を取得することを指しています. ある種のリフレクションと呼んでも良いかもしれません. こういった操作には, JavaSc

    TypeScript をより安全に使うために その 2: オブジェクトの具体的な形にアクセスするのを避ける - Object.create(null)
  • exactOptionalPropertyTypes によせて - Object.create(null)

    TypeScript 4.4 に exactOptionalPropertyTypes というオプショナルなプロパティに関するコンパイラオプションが追加されるのを受けて, そもそもオプショナルなプロパティとは何なのか, どういったときに使うと良いのか, exactOptionalPropertyTypes がどう嬉しいのかを考えてみます. あらかじめ私個人の立場を明らかにしておくと, 型による安全性を重視する傾向があります (やや過激派寄り). exactOptionalPropertyTypes については GitHub の discussion issue での議論も参考になるかもしれません. 前提 そもそもオプショナルなプロパティとは オプショナルなプロパティは, オブジェクト型のプロパティのうち, key?: Type のように ?: で宣言されて, そのプロパティが省略可能である

    exactOptionalPropertyTypes によせて - Object.create(null)
  • 非対称な状態間の同期の実装メモ - Object.create(null)

    状態間の同期は一般的な話題ではあるのですが, 例として React の制御コンポーネントの実装を題材にします. ここで非対称な状態とは, 各状態のとり得る値の集合の間に一対一の対応がないことを指しています. というか一対一に対応するのであればふつうは状態を分けなくてよろしい. まずはおさらいとして, 基的な制御コンポーネントを見てみましょう (sandbox). const MyTextInput: React.VFC<{ text: string; onChange: (text: string) => void; }> = ({ text, onChange }) => ( <input type="text" value={text} onChange={(e) => { onChange(e.target.value); }} /> ); この場合はユーザーが入力するデータと,

    非対称な状態間の同期の実装メモ - Object.create(null)
  • コード中の定数の greppability と TypeScript の進化 - Object.create(null)

    TL; DR コードの greppability のために文字列操作を禁止する目的で string literal type (の union) なら受け付けるが string は受け付けないという関数を作っていたのだけれど, どうにも TypeScript が賢くなりすぎてしまった— 塩水うに (@susisu2413) January 13, 2021 コード中の定数の greppability 以下のように翻訳の ID を引数にとって, 各言語に翻訳されたメッセージを返す関数というのはよくあるのではないかと思います. declare function translate(id: string): string; そして (形式は何でも良いのですが) 各言語に対応した翻訳が書かれているファイルを, (方法は何でも良いのですが) translate が読み込んで使うとしましょう. { "

    コード中の定数の greppability と TypeScript の進化 - Object.create(null)
  • TypeScript の型の再帰上限を突破する裏技 - Object.create(null)

    TypeScript 4.1 で再帰的な conditional type の定義に制限がなくなり (ref), 今後ますます再帰的な型定義をする / 触れることが多くなろうかと思います. 一方で TypeScript が型をインスタンス化する際の再帰の上限はそこそこ厳しく, ちょっと複雑なことをするとすぐに頭を打ってしまいます. 困りましたね. ということで裏技を使ってこの再帰上限を突破する方法を紹介します. 実は以前に型レベル Brainfuck インタプリタを実装した時にも使っていたのですが, あまり知られていないようなので改めて. ちなみにこちらの記事のように TypeScript 自体のコードに手を入れたりはしません. 以下使用している TypeScript のバージョンは 4.1.0-dev.20200911 です. 上限を突破する例 まずは実際に再帰的な型定義を行い, 上限を

    TypeScript の型の再帰上限を突破する裏技 - Object.create(null)
  • Template String Types でパス文字列を解析してクエリする - Object.create(null)

    ※この記事に含まれる内容は TypeScript 4.1 のプレビュー版のものです. 今後仕様が変わり動かなくなる可能性もありますのでご注意ください. 話題の template string types で早速遊んでみます. ゴール .foo[1].bar といった形のパス文字列を型レベルで解析してクエリしちゃいます. こういう感じ: type R1 = Query<{ foo: number }, "">; // R1 = { foo: number } type R2 = Query<{ foo: number }, ".foo">; // R2 = number type R3 = Query<[number, string, boolean], "[1]">; // R3 = string type R4 = Query<{ foo: { bar: string } }, ".fo

    Template String Types でパス文字列を解析してクエリする - Object.create(null)
  • TypeScript で次元つきの物理量を安全に扱う - Object.create(null)

    キーワード: 型レベル整数, 幽霊型 前回の記事の予告通り, TypeScript 4.0 で次元つきの物理量の計算を安全に行うためのライブラリを作ってみました. ただし現状では PoC で, 実用に足るかまでは考慮していません. github.com 物理量についての計算を行う場合, その次元や単位系には特に注意を払う必要があります. 次元の違う値同士 (例えば質量と長さ) の足し算には意味がありませんし, 単位系の違う値同士の計算は誤った結果を導いてしまいます (火星探査機の事故が有名ですね). こういった次元や単位系の取り違えを型システムを使って静的に検出する手法については, Haskell のような型システムが比較的高機能な言語においていくつか先行事例があります (例: dimensional, units). 今回作ったものは, 同様のことを TypeScript でも実現できな

    TypeScript で次元つきの物理量を安全に扱う - Object.create(null)
  • テストの説明に安易に「正しく」とか書かない - Object.create(null)

    みなさんテストは書いていますよね. 書いていなければふりだしに戻る. 例えば関数 add に対して, 以下のようなテストコードがあるとします. describe("add", () => { it("正しく計算できる", () => { expect(add(1, 2)).toBe(3); }); }); よさそうですね? もしよくないと思うのであればここから下は読まなくても大丈夫なくらい理解している方だと思います. 続いて関数名を変えただけのこちらをどうぞ. describe("sub", () => { it("正しく計算できる", () => { expect(sub(1, 2)).toBe(3); }); }); なんだか明らかに間違っている気がします. もしこのテストが通過してしまったとき我々はどうすればよいのでしょうか. 考えられるパターンは 2 つあります. 実装もテストも正

    テストの説明に安易に「正しく」とか書かない - Object.create(null)
  • TypeScript で GADT っぽいの - Object.create(null)

    TypeScript で Haskell にあるような GADT (Generalized Algebraic Data Type) っぽいものをどう表現できるかという話. GADT を使いたくなる例 式をデータとして表現したいことありますよね. あると言ってくれ. 例えば数値と数値上の関数, そして関数適用がある式を考えます. 素朴に表現すると以下のようになるでしょう. type Expr = | { type: "num", val: number } | { type: "fun", val: Fun } | { type: "app", fun: Expr, arg: Expr }; type Fun = (x: number) => number; いちいちオブジェクトリテラルを書くのは面倒なのでコンストラクタを作っておきます. const num = (val: number)

    TypeScript で GADT っぽいの - Object.create(null)
  • TypeScript で型レベル Brainfuck - Object.create(null)

    2024-04-15 追記: 内容をアップデートした記事を書きました. susisu.hatenablog.com TypeScript の型システムはチューリング完全ということが知られていますが, 同じくチューリング完全な言語である Brainfuck のインタプリタを実装することで, その計算能力を確認することができます. この記事のコードは TypeScript 3.8.3 で動作確認しています. ゴール 型レベルで Brainfuck のインタプリタを実装します. type Program = [ ",", ">", ",", "<", "[", ">", "[", ">", "+", ">", "+", "<", "<", "-", "]", ">", "[", "<", "+", ">", "-", "]", "<", "<", "-", "]", ">", ">", ">",

    TypeScript で型レベル Brainfuck - Object.create(null)
  • TypeScript で型レベル階乗 - Object.create(null)

    こんなことがやりたかったんじゃないし, 誰もそんなこと望んじゃいない. でもやる. 動作確認している TypeScript のバージョンは 3.8.3 です. ゴール TypeScript で階乗を計算します. 型レベルで. type F = Factorial<3>; // F = 6 アイデア まずタプル型の length を参照すると, 長さが数値リテラル型で得られるという事実があります. type S = ["foo", "bar", "baz"]["length"]; // S = 3 そして前回の記事でも使ったように, タプル型に対しては要素を追加する / 取り除くといった操作を定義できます. これは長さで言うと +1 / -1 ですね. さらにこれらを (再帰的型定義も使いつつ) 組み合わせることで, より複雑な操作も可能になります. ということは, タプル型と数値リテラル型

    TypeScript で型レベル階乗 - Object.create(null)
  • TypeScript でネストされたオブジェクト型の書き換え - Object.create(null)

    ↓ に対するアンサーソングです. blog.3qe.us 例えばこういう感じの型 T があって, ネストされた内側にある baz の型を number から string に書き換えたいとしますね. type T = { foo: { bar: { baz: number, }, }, }; もしこれが, 書き換える対象のパスを ["foo", "bar", "baz"] のようなタプル型で表現して, Rewrite<T, ["foo", "bar", "baz"], string> のように書けたら素敵だと思いませんか? 私は思います. というわけでやっていきましょう. まずはタプル型に対する head / tail を用意します. type Head<XS extends readonly unknown[]> = XS extends [] ? never : XS[0]; type

    TypeScript でネストされたオブジェクト型の書き換え - Object.create(null)
  • 辞書を作る関数に TypeScript で執拗に型をつける - Object.create(null)

    未来人のみなさまご機嫌いかがでしょうか. この記事が書かれた時点の TypeScript のバージョンは 3.6.4 です. お題 以下の JavaScript の関数に TypeScript で型をつけることを考えます1. function makeDict(prop, entries) { const dict = {}; for (const entry of entries) { dict[entry[prop]] = entry; } return dict; } これは見ての通り, 配列から辞書を作ります2. const entries = [ { id: "a", name: "Foo" }, { id: "b", name: "Bar" }, { id: "c", name: "Baz" }, ]; const dict = makeDict("id", entries);

    辞書を作る関数に TypeScript で執拗に型をつける - Object.create(null)
  • 気がつけば Scala を書いていたので読んだものを列挙するよ - Object.create(null)

    私が読んだものを読んだ順に列挙しているだけです. たぶん何の役にも立ちません. Learn You a Haskell for Great Good! Learn You a Haskell for Great Good! Haskell の入門書. いや冗談ではなく. 代数的データ型とかモナドとか, Scala を書いていても役に立たなかったことがない. 英語版は上のリンクから無料で読めてお得です. 私は日語版書籍の方を読みました. すごいHaskellたのしく学ぼう! 作者: Miran Lipovača,田中英行,村主崇行出版社/メーカー: オーム社発売日: 2012/05/23メディア: 単行(ソフトカバー)購入: 25人 クリック: 580回この商品を含むブログ (73件) を見る Types and Programming Types and Programming Lan

    気がつけば Scala を書いていたので読んだものを列挙するよ - Object.create(null)