序文
グループ内でいくつかの質問やコメントを見ました:なぜ「型体操」がそんなに好きなのですか?TypeScript をまったく学習できないのはなぜですか? 私はタイプ体操をする人が嫌いです。なぜ習った後しばらくすると忘れてしまうのでしょうか?
これらの問題の影響を受けて、最も単純な観点から TypeScript を紹介し、型操作だけが体操ではないことを紹介したいと思います。また、型システムを使用するための基本的なガイドとして、本文で基本的な考え方を紹介します。
プライマー
比較的単純な API の設計プロセスから型について説明します。ここでは、現在ツール開発者であると仮定し、オブジェクトから指定されたキーを取得し、それを外部使用のための新しいオブジェクトとして返す API を設計する必要があります。
ガベージタイプスクリプト
ある人はこう言いました。「型を壊す必要はない。コードを書くときに型を持たずに、ただ好きなものを書きたいだけだ。」次に、このコードを書きました。
declare function pick(target: any, ...keys: any): any
彼のユーザーは黙って次のコードを書きました。
pick(undefined, 'a', 1).b
書いて実行した後、問題が深刻であることがわかりました。コンソールには大量のエラーが報告され、インターフェイス データを送信できませんでした。どうすればよいでしょうか?
TypeScriptを勉強しているところです
ある人はこう言いました。「受信する型を少しチェックしてください。ただ、人々が私にランダムにパラメータを渡さないようにしてください。」
declare function pick(target: Record<string, unknown>, ...keys: string[]): unknown
なるほど、上記の問題はもう存在せず、API は基本的に利用できるようになりました。しかし!オブジェクトが複雑で、フィールドが短い語長ではない場合、未解決の問題が見つかります。
pick({ abcdefghijkl: '123' }, 'abcdefghikjl')
肉眼で見ると前後の不整合を見つけるのは難しいのに、なぜ呼び出し元のユーザーに自分のフィールドが正しく記述されているかどうかを確認させる必要があるのでしょうか。
TypeScriptだけではない
ある人は、「これは簡単ではありません。ジェネリックを使用して keyof を追加するだけです。」と言いました。
declare function pick<
T extends Record<string, unknown>
>(target: T, ...keys: (keyof T)[]): unknown
上記の問題をさらに解決しましたが、!キーが正しい値で渡されるかどうかをチェックする必要はありませんが、実際には戻り値に関して同様の問題が発生します。
pick({ abcdefghijkl: '123' }, 'abcdefghijkl').abcdefghikjl
少しの拡張
ここでは非常に単純な関数のように見えますが、実際にはより重要な情報が含まれています。
以前の方法でユーザーから渡された型情報を取得できないのはなぜですか? これには理由があって、APIを設計する際には型をどうやって検証するかという観点から考えます。
ここでは、合意されたルールを通じて TypeScript の暗黙的な型推論を通じて受信型を取得し、合意されたルールを通じて新しい型制約を変換してユーザーの入力を制限する試みを示します。
数学的 TypeScript
ある人はこう言いました。「扱いは簡単です。新しいタイプを考え出すだけです。」
declare function pick<
T extends Record<string, unknown>,
Keys extends keyof T
>(target: T, ...keys: Keys[]): {
[K in Keys]: T[K]
}
この時点で、私は型の役割について基本を理解しており、開発者が受け入れることができる型を満たす比較的使いやすいコードを書くことができます。さらに特殊なケースをいくつか考えてみましょう。
// 输入了重复的 key
pick({ a: '' }, 'a', 'a')
完璧な TypeScript
この時点で、最初は「体操」タイプを開始しました。しかし、この記事ではそれを分析しません。
export type L2T<L, LAlias = L, LAlias2 = L> = [L] extends [never]
? []
: L extends infer LItem
? [LItem?, ...L2T<Exclude<LAlias2, LItem>, LAlias>]
: never
declare function pick<
T extends Record<string, unknown>,
Keys extends L2T<keyof T>
>(target: T, ...keys: Keys): Pick<T, Keys[number] & keyof T>
const x0 = pick({ a: '1', b: '2' }, 'a')
console.log(x0.a)
// @ts-expect-error
console.log(x0.b)
const x1 = pick({ a: '1', b: '2' }, 'a', 'a')
// ^^^^^^^^
// TS2345: Argument of type '["a", "a"]' is not assignable to parameter of type '["a"?, "b"?] | ["b"?, "a"?]'.
// Type '["a", "a"]' is not assignable to type '["a"?, "b"?]'.
// Type at position 1 in source is not compatible with type at position 1 in target.
// Type '"a"' is not assignable to type '"b"'.
比較的完璧なピック機能が完成しました。
要約する
タイトルに戻りましょう。私が観察したところによると、ほとんどの人はいくつかの理由で TypeScript を使い始めます。
偉い人たちがプレイしているのを見て、私も「プレイ」して型検証用に書きたいと思います。
いくつかの成熟したプロジェクトが TypeScript を使用しているのを見て、コントリビューションに参加したいと考えています。参加プロセス中に、型を渡すために型エラーを解決したいと考えています。
会社の全体的なテクノロジー スタックは TypeScript を使用しており、TypeScript は型の検査とレビューに合格するために型の問題を解決するためにビジネス ライティングに使用されています。
このような問題は他にもたくさんありますが、私はそれらを「型チェックの問題を解決するための」型プログラミングとして分類しています。これが、ほとんどの人が TypeScript に非常に不快感を抱き、彼を嫌いになる理由の 1 つです。実はこれは TypeScript を学ぶ上で良いアイデアではないので、ここではデザイナーの観点から型システムについて考える必要があると思います。いくつかの角度があると思います:
型チェックを実施
タイプヒントがフレンドリー
厳密な型チェック
完全にスケーラブル
これらの観点から API を設計すると、開発者はドキュメントを読んだりサンプルをできるだけ見つけたりすることなく、必要なコードを簡単に作成できることがわかります。
私の共有を通じて、誰もが TypeScript をより深く理解し、JavaScript を保護するためのエコロジーに参加できることを願っています。
作者:一介4188
https://juejin.cn/post/7248599585751515173