簡體   English   中英

Typescript 映射返回類型:交集減少為從不,交集屬性沖突

[英]Typescript mapped return type: intersection reduced to never, conflicting intersection property

目標:使用映射類型查找返回類型,根據輸入類型制作 function 的返回類型。

問題:由於可區分聯合類型的交集存在沖突,我收到一個錯誤,我在概念上理解這一點,但對如何構造我的類型以實現我的目標一無所知。

Type 'Integration' is not assignable to type 'IntegrationTypeData[T]'.
  Type 'IntegrationA' is not assignable to type 'IntegrationTypeData[T]'.
    Type 'IntegrationA' is not assignable to type 'never'.
      The intersection 'IntegrationA & IntegrationB' was reduced to 'never' because property 'name' has conflicting types in some constituents.

我的類型如下所示:

enum Integrations {
  A = 'A',
  B = 'B',
}

type IntegrationMap<M extends { [key: string]: any }> = {
  [Key in keyof M]: M[Key]
};

type IntegrationA = {
  name: Integrations.A,
  propertyA: string;
}

type IntegrationB = {
  name: Integrations.B,
  propertyB: number;
}

type IntegrationData = {
  [Integrations.A]: IntegrationA;
  [Integrations.B]: IntegrationB;
};

// this resolves to type Integration = IntegrationA | IntegrationB
type Integration = IntegrationMap<IntegrationData>[keyof IntegrationMap<IntegrationData>];


// the function I want to make have a dynamic/mapped return type
const getIntegration = <T extends Integrations>(name: T): IntegrationData[T] => {
  // the type of the integrations variable is Integration[]
  const integration = integrations.find((i: Integration) => i.name === name);
  return integration;
};

// desired usage
// typeof intB = IntegrationB
const intB = getIntegration(Integrations.B);

有人可以幫助我了解如何解決此錯誤以及如何正確鍵入數據,以便我獲得此 function 的動態和類型安全返回類型嗎?

integrations數組的元素是聯合類型(IntegrationA | IntegrationB)

如果您查看arrays 的find()方法的默認調用簽名,您會看到它返回元素類型(在本例中為IntegrationA | IntegrationB )或undefined的值。 所以你返回一個類型的值IntegrationA | IntegrationB | undefined IntegrationA | IntegrationB | undefined IntegrationA | IntegrationB | undefined 但是由於您的函數的返回類型是IntegrationData[T]其中T是傳入的name參數的類型。編譯器不能確定前者可以分配給后者,所以它會抱怨。

您收到的特定錯誤消息是關於交集類型IntegrationA & IntegrationB被簡化為never類型,因為確保您返回的Integration[T]獨立T的唯一方法是您的值既是IntegrationAIntegrationB ,這是不可能的。 最好不要太糾結於錯誤消息。

可以說這里的問題是find()的返回類型對於您的目的來說太寬了。


幸運的是find()有另一個調用簽名,它有可能返回比數組元素類型更窄的類型(但仍然可能是undefined )。 如果您傳入的回調是用戶定義的類型保護 function ,其返回類型謂詞的形式x is Y ,那么將返回縮小的類型Y | undefined Y | undefined

如果編譯器能夠理解i => i.name === name充當類型保護 function 並帶有調用簽名(i: Integration) => i is IntegrationData[T] ,那就太好了。 不幸的是,這並沒有發生; TypeScript 不會從實現中推斷類型保護 function 調用簽名。 在某些情況下,在microsoft/TypeScript#38390有一個開放的請求來支持這一點,但目前它不是語言的一部分。 (即使是這樣,在這種情況下的這種推斷也可能超出了它的能力。)

如果你想使用i => i.name === name作為類型保護 function 你需要這樣注釋

const getIntegration = <T extends Integrations>(name: T): IntegrationData[T] => {
  const integration = integrations.find(
    (i: Integration): i is IntegrationData[T] => i.name === name
  // annotated ---> ^^^^^^^^^^^^^^^^^^^^^^^^^
  );
  return integration!;
};

注釋可以讓您大部分時間到達那里。 不過,它仍然沒有消除undefined 就編譯器所知, integrations實際上並沒有IntegrationData[T]類型的元素。 所以integration可能是undefined的。 您可以通過在return之前編寫if (!integration) throw new Error("OH NO I WAS WRONG")來明確處理此問題。 或者,如果您確定它實際上不是undefined ,您可以通過使用非空斷言運算符 (!)告訴編譯器。 寫作return integration! ,您聲稱integration不會undefinednull ,因此類型的值IntegrationData[T] | undefined IntegrationData[T] | undefined可以被視為一個IntegrationData[T]

現在它編譯沒有錯誤。

Playground 代碼鏈接

暫無
暫無

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

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