対応するコンポーネントを使用したTypeScriptジェネリックの使用


Colin CassidyUnsplashによる写真
最近、私はDESにここで見つけました.あなたが気づいているかもしれないが、私は非常にしばらくの間、私はTSと一緒に仕事をしてきました、そして、私が反応で仕事をしようとした最初のものはジェネリックでした.なぜなら、彼らは私たち、コンポーネントクリエイターによって、エンドユーザー、コンポーネント消費者にタイプをコントロールすることを可能にする驚くべき機能であるからです.多分、我々は両方とも、多分、我々は1つであるかもしれません.とにかく、良いタイプされたコンポーネントは、常に助けます.
しかし、その記事は正確でありませんでした、そして、それは未完成でした、それで、他の誰かがそれを読むならば、彼らは誤報で終わります.そして、私たちは理解しています、我々全員はここで学んでいます、我々全員は間違いをします、そして、それは我々が学ぶためにそれほど重要でありません.それで、私はジェネリックであることをあなたに示すつもりです、そして、どのように反応でそれらを使用するか.また、なぜあなたが今読んで良い方法でそれらを使用することはできませんので、あなたは、後悔することはできません.

ジェネリックとは何か
一般的なタイピングでは、後で定義される型で動作できます.これにより、特定のタイプの作業を必要とする関数やコンポーネントを再利用することができます.あるいは、JSを使用しているので、入力を省略することができます.
一般的なタイピングを型の変数と考えることができます.あなたはそれらを宣言することができます、彼らは範囲を持っています、そして、あなたは望むように彼らを使うことができます.

タイプスクリプトはどのようにジェネリックを使用するか?
TerescriptはC - Chorhnで大きく影響されているので、Cのような構造があり、これは例外ではありません.タイプスクリプトは、アングルブレーキ(<>)で、Cと同じようにジェネリックを定義して、使用します.それで、ジェネリックを使用するために、我々はアングルブレーキで彼らを宣言する必要があります.
機能中の

  • // Using named functions
    function identity<Type>(arg: Type): Type {
      return arg;
    }
    
    // Using inline typing and arrow function
    const identity: <Input>(arg: Input) => Input = (arg) => arg;
    
    // Using arrow function with typing
    const identity = <Input>(arg: Input): Input => arg;
    
    // Using an interface as a type
    interface GenericIdentityFn {
      <Type>(arg: Type): Type;
    }
    
    const identity: GenericIdentityFn = (arg) => arg;
    
    クラスの

  • class GenericNumber<NumType> {
      zeroValue: NumType;
      add: (x: NumType, y: NumType) => NumType;
    }
    
    ジェネリックはまた、制約を使用して、ユーザーが使用する型を確実にすることができます.制約を定義するには、キーワードextendsを使用します.また、条件付きタイピングと呼ばれる機能で使用される、ロジックOR(|)とAND(&)、および3次条件[condition] ? [return if true] : [else return]のようないくつかの演算子を使用することもできます.
    それで、最後の例を使って書きます.
    class GenericNumber<NumType extends number | bigint> {
      zeroValue: NumType;
      add: (x: NumType, y: NumType) => NumType;
    }
    
    以下のようにします.
    const num = new GenericNumber<number>();
    const big = new GenericNumber<bigint>();
    
    num.zeroValue; // type number
    big.zeroValue; // type bigint
    
    num.zeroValue * big.zeroValue // Operator '*' cannot be applied to types 'number' and 'bigint'.(2365)
    
    Playground link

    タイプスクリプトとJSX
    たぶん、あなたはこの点でそれに気がつきます、しかし、JSXとTSは両方とも彼らの構文でアングルブレーキを使います、それで、あなたが要素を定義するために、そして、ジェネリックタイプを定義するときそれを使うとき、tsはどのように理解することができますか?
    できません.
    そして、それゆえ、私たちは、JSXをTSで使用するために特定の規則に従わなければならないのです.この最初の規則は重要です.なぜなら、それはあなたがJSX要素を定義するためにアングルブレーキを使用することをTSに伝えるからです.そして、そのために、私たちがJSXで働いている間、私たちがTSジェネリックと共に長くすることができないいくつかのことがあります.
    // Using arrow function with typing
                                // ^ Error: JSX element 'Input' has no corresponding closing tag.
    const identityWithTypedFn = <Input>(arg: Input): Input => arg;
    
    Typescript Playground
    しかし、私たちはまだジェネリックを使用するために名前付き関数を使うことができました、しかし、我々は機能的な構成要素として彼らをタイプすることができません.引数をpropsとして型を指定でき、戻り値の型を宣言することができますが、関数構成要素が持つ追加のプロパティはtsxのようにはなりません.さて、これについて考えてみると、私たちはそれらをカバーするためにTSを使用しているので、それはそんなに悪いことではないかもしれませんが、私たちは、これを使用するものではないことを考慮する必要がありますし、それらは強く型付け機能コンポーネントを使用したいと思います.

    それで、どのように、私は反応成分でジェネリックを使うことができますか?
    そうではないが、型の宣言を行う方法がない.このためにバグが開いている(Typescript#22063)が、代わりに型別名を作成したいならば.私には、この正確なことについて最近書いたポストがあります.


    export interface Component extends VFC<ComponentProps<{}>> { <Data>(props: ComponentProps<Data>): ReturnType<FC> };
    ...
    export const Component: Component = ({ data, keys }: ComponentProps<Record<any, any>>) => {
      ...
    }
    
    Tsはどのように型マージを扱うかのため、必要なときに値をとり、必要に応じて型をとります.しかし、これはハイレベルタイピングの良い例です.私は、これがどんな機能的なトレードオフも持っていないので、開いたバグで使われることを提案します、そして、誰かは言いました:

    The trade off is complexity / readability. Although Typescript projects often already have their fair share of arcane expressions. Luckily you can hide most of them away so junior devs can just use the types without thinking about them too much (if the code base is in an okay state)


    それに賛成です.もし誰かがジェネリックを使用することを学んでいるならば、彼らがやって来た最後のことは、彼らがこれについて考えれば、そのようなものになるでしょう.私は最近、これについて知りました、そして、私が数年前にこれを見るならば、私はそれを理解しないでしょう.理解するのは難しいですが、私たちは、型の型、関数シグネチャのオーバーロード、型と値のマージを扱っています.
    良いことは、あなたがする必要はありません.あなたが何かを理解していないならば、あなたがそれを使用しないのは最高です.そして、あなたがそれを理解するならば、あなたはおそらく経験豊かなプログラマーが消費する何かを届けます、そして、このことは彼らを助けます.

    それはすべての人々です!
    読んでいただきありがとうございます、そして、私は本当にこれはあなたが一般的なTS上で動作する方法を理解するのを助けることができると私たちが好きなように我々はなぜそれらを使用することができないことを願っています.
    あなたが質問をするならば、彼らに尋ねることについて疑いません、私は答えを試みます.
    ハッピーコーディング!