簡體   English   中英

打字稿:將聯合類型映射到單一類型

[英]Typescript: map union type to a single type

我試圖縮小(w/推斷)我想要從這個數組過濾器中取出的類型,但它給了我一個 TypeError: 'Item' is missing the following properties

type ItemList = (Item | ItemGroup )[];
type ItemGroup = {
  name: string;
  items: Item[];
}
type Item = {
  key: string;
  label: string;
}

const list: ItemList = [
   {
      key: 'key',
      label: 'label'
   },
   {
      name: 'name',
      items: [
        {
          key: 'key1',
          label: 'label2'
        },
        {
          key: 'key3',
          label: 'label4'
        },
      ]
   }
]

const groups: ItemGroup[] = list.filter( l => 'name' in l )
      ^^^^^^
// Type '(Item | ItemGroup)[]' is not assignable to type 'ItemGroup[]'.
//   Type 'Item | ItemGroup' is not assignable to type 'ItemGroup'.
//     Type 'Item' is missing the following properties from type 'ItemGroup': name, items ts(2322)

有任何想法嗎?

您有一個包含ItemItemGroup元素的數組。 您希望將此數組過濾為僅包含ItemGroup的元素,並且您希望打字稿了解您已過濾列表並知道返回的類型為ItemGroup[]

如何實現這一點是購買將l => 'name' in l的過濾器轉換為它自己的類型保護函數。 返回類型value is ItemGroup告訴打字稿“當且僅當這是真的,值的類型是 ItemGroup”。

const isItemGroup = (value: Item | ItemGroup): value is ItemGroup => 'name' in value;

const groups: ItemGroup[] = list.filter( isItemGroup );

通過使用類型保護,打字稿可以理解list.filter的含義,你的錯誤就會消失。

游樂場鏈接

不幸的是,編譯器不夠聰明,無法查看l => "name" in l回調中的l => "name" in l並理解它可用於縮小Item | ItemGroup Item | ItemGroup只是一個ItemGroup 幸運的是,您可以通過將其注釋為用戶定義的類型保護函數告訴編譯器這是意圖:

const isItemGroup = (l: Item | ItemGroup): l is ItemGroup => "name" in l;

現在,如果您調用isItemGroup(l)並且結果為true ,則編譯器將理解l是一個ItemGroup 此外,標准庫Array.prototype.filter()提供了一個調用簽名,它接受用戶定義的類型保護回調並生成一個縮小的數組。 因此,通過使用isItemGroup作為回調,您可以獲得所需的結果:

const groups: ItemGroup[] = list.filter(isItemGroup); // no error now

Playground 鏈接到代碼

您可以使用類型 assertion 斷言過濾后的結果數組的類型為ItemGroup[]

const groups: ItemGroup[] = list.filter( l => 'name' in l ) as ItemGroup[]

暫無
暫無

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

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