簡體   English   中英

Typescript接口泛型擴展

[英]Typescript interface generics extends

給定以下界面:

interface IMyInterface<T extends { [key: string]: number }> {
    target: T;
    to:  T;
}

我想將其更改為

interface IMyInterface<T extends { [key: string]: number }> {
    target: P extends T;
    to:  T;
}

目標可以是任何對象,只要它包含T中定義的屬性即可。

例:

let obj = <IMyInterface>{
    target: { name:"John", age: 100 },
    to: { age: 200 }
}

打字稿編譯器應在以下情況下抱怨:

let obj = <IMyInterface>{
    target: { name:"John", y: 1980 },
    to: { x: 20 }
}

“目標”中缺少“ x”屬性的位置

let obj = <IMyInterface>{
    target: { name:"John", x: "20" },
    to: { x: 30 }
}

類型錯誤的地方(數字與字符串)

即我要對目標進行類型檢查,以便它包含“ T”泛型中定義的所有屬性。

我希望將此作為一個對象。

創建類似的方法

methodName<T extends { [key: string]: number }>(target: T, to: T){

}
// and calling it
methodName({ name:"John", x: "20" },{x:30});

即使用“ target”和“ to”的單獨參數工作,並且Typescript中的類型檢查是完美的,但是我需要將“ target”和“ to”封裝在一個對象中,以便可以使用類似以下方法:

methodName<IMyInterface>(object: IMyInterface){

並這樣稱呼它:

methodName({ target: { name:"John", age:20 }, to: { age: 30}});

謝謝你的幫助

首先IMyInterface的幾句話:首先,每當編寫IMyInterface ,都需要指定type參數。 就像是

let obj = <IMyInterface> { // error
    target: { name:"John", age: 100 },
    to: { age: 200 }
}

始終會出錯,因為您遺漏了type參數。 這將起作用:

let obj = <IMyInterface<{ age: number }>> {
    target: { name:"John", age: 100 },
    to: { age: 200 }
}

或者,更常見的是,對於TypeScript,您可以注釋變量的類型,而不是聲明值的類型:

let obj: IMyInterface<{ age: number }> = {
    target: { name:"John", age: 100 },
    to: { age: 200 }
}

如果您的IMyInterface定義指定了默認類型參數 ,則IMyInterface 類型參數 ,但這將無法按您希望的方式工作,因為默認值始終是相同的,並且您希望根據類型更改某些內容to屬性。


我的下一個問題是:您是否希望P僅用於檢查是否正確創建了IMyInterface<T> 因此,一旦創建了有效的IMyInterface<T>您就可以立即忘記使用P嗎? 看起來像它。 在那種情況下,我要做的是將P排除在IMyInterface<T>的定義之外,而使用輔助方法。 您注意到一種方法可以幫助您鍵入檢查,但您需要一個對象,對嗎? 好了,helper方法可以返回一個有效的IMyInterface<T>

namespace HelperFunctionSolution {

  // original definition
  interface IMyInterface<T extends { [key: string]: number }> {
    target: T;
    to: T;
  }

  // helper method
  function makeMyInterface<T extends { [key: string]: number }, P extends T>(
    target: P, 
    to: T
  ): IMyInterface<T> {
    return { target, to };
  }

現在,您可以使用輔助方法:

  const goodObj = makeMyInterface({ name: "John", age: 100 }, { age: 200 }) // okay

如果檢查goodObj您將看到它是goodObj IMyInterface<{age: number}> 編譯器抱怨您想要在哪里:

  const badObj0 = makeMyInterface({}, { x: 30 }) // x is missing
  const badObj1 = makeMyInterface({ name: "John", y: 1980 }, { x: 30 }) 
    // complains about extra property but real problem is x

  const badObj2 = makeMyInterface({ x: "20" }, { x: 30 }) // complains about string 
  const badObj3 = makeMyInterface({ name: "John", x: "20" }, { x: 30 }) 
    // complains about extra property but real problem is x

現在,您可以創建所需的方法:

  class Hmm {
    methodName<T extends { [key: string]: number }>(target: T, to: T) { /*impl*/ }

等等,那是您的定義,但我認為您希望它采用這樣的對象:

    realMethodName<T extends { [key: string]: number }>(
      myInterface: IMyInterface<T>
    ) { /*impl*/ }
  }

並使用它, 確保使用helper函數

  const hmm = new Hmm();
  hmm.realMethodName(makeMyInterface({ name: "John", age: 20 }, { age: 30 })); // okay

}

您不能在其中使用對象文字並保證類型檢查,因為只有助手函數在乎P 因此,這是一種方法,但是您需要使用輔助函數。


另一種可能是您在IMyInterface定義中隨身攜帶了P類型。 這可能不是您想要的,但是它具有令人滿意的效果,您可以在methodName方法中使用字符串文字,並且不需要幫助函數:

namespace TwoTypeParameterSolution {

  interface IMyInterface<T extends { [key: string]: number }, P extends T> {
    target: P;
    to: T;
  }

  class Hmm {
    realMethodName<T extends { [key: string]: number }, P extends T>(
      myInterface: IMyInterface<T,P>
    ) { /*impl*/ }
  }
  const hmm = new Hmm();
  hmm.realMethodName({target: { name: "John", age: 100 }, to: { age: 200 }}) // okay
  hmm.realMethodName({target: {}, to: { x: 30 }}) // x is missing
  hmm.realMethodName({target: { name: "John", y: 1980 }, to: { x: 30 }}) 
    // complains about extra property but real problem is x

  hmm.realMethodName({target: { x: "20" }, to: { x: 30 }}) // complains about string 
  hmm.realMethodName({target: { name: "John", x: "20" }, to: { x: 30 }}) 
    // complains about extra property but real problem is x

  hmm.realMethodName({ target: { name: "John", age: 20 }, to: { age: 30 } }); // okay
}

兩種方法都應該為您工作。 希望能有所幫助; 祝好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM