TypeScript(二)インタフェース

8637 ワード

TypeScriptの核心は,値が持つ構造をタイプチェックすることである.インタフェースは行為と規範を規定し、制限と規範の役割を果たす.
インタフェースは、interfaceキーワード宣言を使用します.一般的な頭文字は大文字で、tsネーミング仕様に従って、インタフェース名に接頭辞Iを付けます.
この文書には、オブジェクトタイプ、関数タイプ、インデックス可能なタイプ、ブレンドタイプのインタフェース、および継承インタフェースが含まれます.
オブジェクトタイプのインタフェース
関数呼び出し時に入力されたオブジェクトのプロパティをチェックするには、次のようにします.
function getFoodInfo({ name, color }: {name: string, color: string}): string {
  return `the ${name} color is ${color}!` 
}

上記の例をインタフェースで説明します.
interface IFood {
  name: string;
  color: string;
}

function getFoodInfo({ name, color }: IFood): string {
  return `the ${name} color is ${color}!` 
}

getFoodInfo({
  name: 'cake',
  color: 'white'
})

タイプインスペクターは、対応するプロパティが存在し、タイプが一致している限り、プロパティの順序をチェックしません.
オプション属性
インタフェースのプロパティはすべて必要ではありません.特定の条件で存在するプロパティもあります.
オプション属性を持つインタフェースは、オプション属性名定義の後に?記号を付けるだけです.
interface AreaConfig {
  name: string;
  width?: number;
}

// width       
function getAreaInfo ({ name, width }: AreaConfig): { name: string, square: number } {
  const area = { square: 9, name }

  if (width) area.square = width * width
  return area
}

getAreaInfo({name: 'beijing'})

オプション属性のメリット:
  • は、存在する可能性のある属性を事前定義することができる
  • .
  • 存在しない属性を参照するときに投げ出すエラー
  • を事前にキャプチャする.
    例:
    interface AreaConfig {
      name: string;
      width?: number;
    }
    
    // width       
    function getAreaInfo ({ name, width }: AreaConfig): { name: string, square: number } {
      const area = { square: 9, name }
    
      // width    widt
      if (widt) area.square = width * width //  Cannot find name 'widt'.
      return area
    }
    
    //        width  , js      widt      width     undefined。   ts                    。
    getAreaInfo({ name: 'beijing', width: 12 })
    

    読み取り専用プロパティ
    一部のオブジェクトのプロパティは、オブジェクトの作成後に変更できません.属性名には、readonlyを使用して読み取り専用属性を指定できます.
    オブジェクトのプロパティ
    interface Food {
      readonly name: string;
      color: string;
    }
    
    const tomato: Food = {
      name: 'tomato',
      color: 'red'
    }
    tomato.name = 'potato' // Cannot assign to 'name' because it is a read-only property.
    
    ReadonlyArray可変配列を作成できますReadonlyArrayのタイプはArrayと似ていますが、すべての可変メソッドを削除するだけなので、配列が作成されてから変更されないことを確認できます.
    通常の配列を定義します.
    let arr: Array = [1, 2, 3]
    arr[1] = 4
    console.log(arr) // [1, 4, 3]
    

    変更できない配列を作成します.
    let array: ReadonlyArray = [5, 6, 7, 8]
    

    配列のプロパティ:
  • 修正不可項目:
  • array[1] = 55 
    // Index signature in type 'readonly number[]' only permits reading.
    
  • 削除不可、要素追加
  • array.push(7) 
    array.splice(0, 1)
    // Property 'splice' does not exist on type 'readonly number[]'.
    
  • 配列length属性
  • は変更できません.
    array.length = 6
    // Cannot assign to 'length' because it is a read-only property.
    
  • ReadonlyArray全体を通常の配列に割り当てることはできません.
  • arr = array
    // The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
    

    ただし、タイプ断言で書き換えることはできます.
    arr = array as number[]
    arr[1] = 555
    
    console.log(array === arr) // true
    // array   arr         ,      arr   array   ,           array       
    
    array[1] = 111 // Index signature in type 'readonly number[]' only permits reading.
    
    readonly vs constの違いconstで定義された変数は再割り当てできませんが、その属性値は変更できますが、readonlyで定義された属性は変更できません.
    追加属性チェック
    まず例を見てみましょう.
    interface Food {
      name: string;
      size: number;
      color?: string;
    }
    
    function getFood(info: Food): string {
      return `${info.name} size is ${info.size}, color is ${info.color}` 
    }
    
    getFood({ name: 'tomato', size: 10, colorX: 'red'})
    // Argument of type '{ name: string; size: number; colorX: string; }' is not assignable to parameter of type 'Food'.
    // Object literal may only specify known properties, but 'colorX' does not exist in type 'Food'.
    

    getFoodを呼び出すときにcolorスペルエラーが発生します.colorはオプションなので互換性があるので問題ありません.しかしtsタイプインスペクタはcorXという追加属性を検出し、エラーを投げ出す.
    TSを迂回して追加属性のチェックには3つの方法があります.
    1.型断言(最も簡単な方法)
    getFood({ name: 'tomato', size: 10, colorX: 'red'} as Food)
    

    2.文字列インデックス署名(最適)
    interface Food {
      name: string;
      size: number;
      color?: string;
      [propName: string]: any;
    }
    

    3.オブジェクトを別の変数に割り当てる(タイプ互換性)
    const obj = { name: 'tomato', size: 10, colorX: 'red' }
    getFood(obj)
    

    関数のタイプ
    インタフェースは、プロパティ付きの通常のオブジェクトに加えて、関数タイプも記述できます.
    インタフェースを使用して関数タイプを表す場合は、インタフェースに呼び出し署名を定義して、関数のパラメータと戻り値のタイプを記述する必要があります.次のようになります.
    interface FuncInterface {
      (num1: number, num2: number): number
    }
    
    let add: FuncInterface = (n1, n2) => {
      return n1 + n2
    }
    add(2, 5)
    

    パラメータ名はインタフェースで定義したパラメータ名と同じである必要はありません.またTypeScriptのタイプシステムではパラメータタイプが推定されるため、パラメータタイプは指定しなくてもよい.関数の戻り値タイプは、戻り値によって推定されます.指定しないこともできます.
    インデックス可能なタイプ
    インデックス可能なタイプは、インデックスによって得られるタイプを記述します.例えばarr[1]やperson.name.はっきり言って、配列やオブジェクトが従う仕様と制約です.インデックス可能なタイプには、インデックスのタイプと対応するインデックス戻り値のタイプを記述するインデックス署名があります.
    次の例では、配列をインタフェースで表します.StringArrayインタフェースのインデックス署名タイプはnumber、インデックス署名の戻り値タイプはstringです.
    interface StringArray {
      [index: number]: string;
    }
    const arr: StringArray = ['red', 'pink']
    

    インデックス署名には、数値と文字列の2つの形式があります.
    1.数値:
    interface Arr {
      [index: number]: number
    }
    const arr: Arr = [1,2,3]
    

    2.文字列:
    interface PropString {
      [prop: string]: number
    }
    
    const objStr: PropString = {
       success: 1,
       failed: 0
    }
    

    インデックス署名を読み取り専用に設定することで、インデックスに値を割り当てることを防止できます.
    interface Sina {
      readonly [index: number]: string
    }
    const sian: Sina = {
      1: 'sina'
    }
    sian[1] = 9 // Index signature in type 'Sina' only permits reading
    

    両方のタイプのインデックスを同時に使用できますが、数値タイプのインデックスに対応する戻り値は、数値をインデックスとして使用するとjavascriptが数値を文字列に変換してオブジェクトをインデックスするため、文字列タイプのインデックスが値のサブタイプを返す必要があります.
    次の例では、stringタイプ属性の戻り値はstringタイプであるため、numberタイプ属性の戻り値はstringのサブタイプ(stringを含む)である必要があります.
    //   
    interface PropType {
      [id: number]: string;
      [propName: string]: string;
    }
    
    //   
    interface PropType {
      [id: number]: number;
      [propName: string]: any;
    }
    
    //   
    interface PropType {
      [id: number]: number;
      [propName: string]: string;
    }
    // Numeric index type 'number' is not assignable to string index type 'string'.
    

    注意:インデックス可能な署名が定義されると、必須属性とオプション属性の戻り値タイプは、そのタイプの戻り値のサブセットである必要があります.
    次の例では、ageのタイプがインデックス・タイプの戻り値のタイプと一致しないため、エラーが発生します.
    interface Test {
      name: string;
      age?: number; // Property 'age' of type 'number' is not assignable to string index type 'string'.
      [prop: string]: string;
    }
    

    インタフェースの継承
    クラスと同様に、インタフェースも継承できます.
    interface BaseInfo {
      name: string,
      age: number
    }
    
    interface AddressInfo extends BaseInfo {
      address: string
    }
    
    const userInfo: AddressInfo = {
      name: 'jack',
      age: 12,
      address: 'shanghai'
    }
    

    複数のインタフェースを継承:
    interface AllInfo extends BaseInfo, AddressInfo {
      hobby: string
    }
    
    const allInfo: AllInfo = {
      name: 'mike',
      age: 12,
      address: 'beijing',
      hobby: 'song'
    }
    

    ブレンドタイプ
    関数もオブジェクトであり、独自の属性や方法もあります.
    関数変数を実行するたびに1を加算する変数があるとします.
    JavaScriptの実装
  • グローバル変数の定義:
  • let count = 0
    const add = () => count++
    

    以上の方式countはグローバル役割ドメインで定義され,明らかに役割ドメインである.パッケージを閉じる方法:
  • 閉パッケージ
  • const getCount = () => {
      let count = 0
      return () => count++
    }
    const add = getCount()
    add()
    
  • 関数属性
  • const getCount = () => {
      getCount.count++
    }
    getCount.count = 0
    getCount()
    

    TypeScriptハイブリッドタイプインタフェースで実現
    interface Counter {
      //           
      (): void;
      //        
      count: number;
      //         
      rest(): void;
    }
    
    //       ,     Counter     
    function getCounter(): Counter {
      const getCount = () => {
        getCount.count++
      }
      getCount.count = 0
      getCount.rest = function () {
        this.count = 0
      }
      return getCount
    }
    
    const getCount = getCounter()
    getCount()        // 1
    getCount()        // 2
    getCount.rest()   // 0