製品の品質を落とさずに開発チームを拡大する方法
開発チームの規模を拡大中ですか?製品の品質を犠牲にすることなく成長する方法を学びましょう。このガイドでは、スケールする時期、チーム構成、採用、リーダーシップ、ツールなどの兆候に加え、The Codestがどのように...
ジェネリックスは、単一の型ではなく、複数の型を扱う再利用可能なコードの断片を提供する。ジェネリックスは、型を変数として扱い、関数のパラメータと同様に使用時に指定する方法を提供する。
ジェネリックは、関数(ジェネリック関数の作成)、クラス(ジェネリッククラスの作成)、インターフェース(ジェネリックインターフェースの作成)と組み合わせて使用することができます。
ジェネリックの最も一般的な使い方は配列の宣言である:
const myArray: string[];一見したところ、それほど特別なことでもない。 my配列 を文字列の配列として宣言しても、ジェネリック宣言と同じである:
const myArray:Array;このバニラJSの関数をTypeScriptに移植するにはどうしたらいいか:
関数 getPrefiledArray(filler, length) { { (new Array(length)).fill(filler).
    return (new Array(length)).fill(filler);
}この関数は、指定された量の フィラーだから 長さ は 番号 の配列を返します。 フィラー - しかし、フィラーとは何だろう?この時点では何でもいい。 いずれも:
function getPrefiledArray(filler: any, length: number): any[] {.
    return (new Array(length)).fill(filler);
}使用 いずれも 文字どおり何でも渡せるので、定義にある「単一の型ではなく複数の型を扱う」ことは完全にカバーされている。 フィラー 型と戻り値の型を定義する。この場合、ある共通のものを返したいので、この共通のものを明示的に 型パラメータ:
function getPrefiledArray(filler: T, length: number):T[] {
    return (new Array(length)).fill(filler);
}のように使用する:
const prefilledArray = getPrefiledArray(0, 10);別の、おそらくより一般的なケースを見てみよう。なぜ関数で型を使うのだろうか?私にとっては、関数に渡される引数が、自分が操作したい何らかのプロパティを持つことを保証するためだ。
もう一度、単純なバニラJS関数をTSに移植してみよう。
関数 getLength(thing) {
    thing.lengthを返す;
}私たちは自明ではない難問を抱えている。 長さ というようなことを最初に考えるかもしれない:
関数getLength(thing: typeof Array):number { {.
    thing.lengthを返す;
}文脈によっては正しいかもしれないが、全体的には少し汎用的である。複数の型の配列で動作するが、そのモノが常に配列であるべきなのかどうかがわからない場合はどうだろう。この場合、オブジェクトのプロパティを定義できる構造体、つまりインターフェースに、そのモノに共通するプロパティを集めなければならない:
インタフェース IThingWithLength {
  length: 数;
}を使うことができる。 IThingWithLength インターフェイスのタイプとして もの パラメータが必要だ:
function getLength(thing: IThingWithLength):number { {.
    thing.lengthを返す;
}率直に言って、この単純な例では全く問題ないが、もしこの型を汎用的なものに保ち、最初の例のような問題に直面しないようにしたいのであれば、次のように使うことができる。 一般的な制約:
function getLength(thing: T):number { 次のようになります。
    thing.lengthを返す;
}そしてそれを使う:
interface IBananaPeel { インターフェース バナナピール
  厚さ:数値
  長さ:数値;
}
const bananaPeel:IBananaPeel = {thickness: 0.2, length: 3.14};
getLength(bananaPeel);使用 拡張 を保証する。 T によって定義されるプロパティが含まれます。 IThingWithLength.
ここまではジェネリック関数を扱ってきたが、ジェネリックが輝く場所はそれだけではない。
まず、バナナの束をバナナ・バスケットに入れてみよう:
クラス Banana {
  コンストラクタ(
    public length: 数、
    public color: string、
    public ionizingRadiation: 数
  ){}
}
class BananaBasket { バナナバスケット
  private bananas: Banana[] = [];
  add(banana: バナナ): void { }.
    this.bananas.push(banana);
  }
}
const bananaBasket = new BananaBasket();
bananaBasket.add(new Banana(3.14, 'red', 10e-7));では、同じタイプで異なるものを入れる汎用バスケットを作ってみよう:
クラス Basket {
  private stuff:T[] = [];
  add(thing: T): void { この.stuff.push(thing)
    this.stuff.push(thing);
  }
}
const bananaBasket = new Basket();最後に、私たちのバスケットが放射性物質の容器であり、放射性物質を含む物質しか保管できないと仮定しよう。 電離放射線 財産である:
インターフェース IRadioactive {
  ionizingRadiation: number;
}
class RadioactiveContainer { 以下のようなものがあります。
  private stuff:T[] = [];
  add(thing: T): void { {.
    this.stuff.push(thing);
  }
}最後に、私たちの知識を総動員して、ジェネリック・インターフェースを使った放射能帝国を作ってみよう:
// コンテナの共通属性を定義する
インターフェース IRadioactive {
  ionizingRadiation: number;
}
// 放射性物質を定義する
interface IBanana extends IRadioactive { 以下のように定義します。
  length: 数
  color: 文字列;
}
// 放射性でないものを定義する
インターフェース IDog {
  weight: 数字;
}
// 放射性のものだけを入れるコンテナのインターフェイスを定義する
interface IRadioactiveContainer { 以下のように定義します。
  add(thing: T): void;
  getRadioactiveness():数値;
}
// 放射性コンテナ・インターフェースを実装するクラスを定義する
class RadioactiveContainer implements IRadioactiveContainer { } // 放射性コンテナインターフェイスを実装するクラスを定義する。
  private stuff:T[] = [];
  add(thing: T): void { この.stuff.push(thing)
    this.stuff.push(thing);
  }
  getRadioactiveness():数値{。
      return this.stuff.reduce((a, b) => a + b.ionizingRadiation, 0)
  }
}
// ERROR!型 'IDog' は制約 'IRadioactive' を満たしていません。
// そして、犬を放射性コンテナの中に格納するのはちょっと残酷だ。
const dogsContainer = new RadioactiveContainer();
// すべて順調!
const radioactiveContainer = new RadioactiveContainer();
// 放射性廃棄物の分別を忘れずに - バナナだけ別のビンを作る。
const bananasContainer = new RadioactiveContainer();以上です!