簡體   English   中英

Typescript/Angular 10:具有通用聯合類型的組件

[英]Typescript/Angular 10: component with generic union type

我有以下接口:

export interface Channel {
  id: number;
  name: string;
}

export interface TvChannel extends Channel {
  subscribed: boolean;
}

export interface RadioChannel extends Channel {
  // marker interface to distinguish radio channels from TV channels
}

和一個 angular 組件:

// ./channel.ts

@Component({
  selector: 'channel',
  templateUrl: './channel.html'
})
export class ChannelComponent<T extends TvChannel | RadioChannel> {
  @Input() channel: T;
  (...)
}

使用以下模板

<!-- ./channel.html -->
<div>{{ channel.id }} </div>
<div *ngIf="channel.subscribed !== undefined">{{ channel.subscribed }} </div>

我的問題是我在模板上遇到編譯錯誤,因為無法解析channel.subscribed 我知道它適用於channel.id ,因為這是TvChannelRadioChannel類型(即這些類型之間的交集)中的屬性。 但是我想要一個可以處理這兩種類型的組件(即兩種類型的聯合)。

這可能嗎?

當你做這樣的聯合時——你最終得到的 T 只是可分配給 TvChannel 和 RadioChannel 的類型。 從您的 inheritance 設置中,這只會是頻道。

您可以使用類型保護來處理這種行為 - https://www.typescriptlang.org/docs/handbook/advanced-types.html - 您使用類型保護來斷言您的類型實際上是一種類型或另一種類型。

但是,根據您的代碼,我認為這不是您所追求的確切行為。

您似乎想要類型的聯合 - 其中特定類型特有的屬性是可選的,而共享的屬性是在 Channel 中定義的。

這是我輸入的方式。 我已將屬性 foo 添加到 RadioChannel 以測試它的行為是否正確

類型:

export interface Channel {
  id: number;
  name: string;
}

export interface TvChannel extends Channel {
  subscribed: boolean;
}

export interface RadioChannel extends Channel {
  // marker interface to distinguish radio channels from TV channels
  foo: string;
}

幫手類型。 這里的想法是構造兩組密鑰。 UniqueKeys<T, U> 是一組鍵,僅存在於一個 object 或另一個上,但不存在於兩者上。 CommonKeys<T, U> 則相反。


type UniqueKeys<T, U> = Exclude<keyof T, keyof U> | Exclude<keyof U, keyof T>;

// Test unique keys
type ChannelUniqueKeys = UniqueKeys<TvChannel, RadioChannel>; // "subscribed" | "foo"

type CommonKeys<T, U> = keyof T & keyof U;
// Test common keys
type ChannelCommonKeys = CommonKeys<TvChannel, RadioChannel>; // "id" | "name"

現在我們根據這兩個鍵集將它們重建回 object 個切片,從 (T & U) 中查找正確的值——兩種類型的組合。


type UniqueObjectSlice<T, U> = {[key in UniqueKeys<T, U>]: (T & U)[key]};
type CommonObjectSlice<T, U> = {[key in CommonKeys<T, U>]: (T & U)[key]};

最后我們可以構造 PartialUnion<T, U>。 現在這只是獨特的 object 切片的部分(使所有屬性都可選),結合了公共的 object 切片:

type PartialUnion<T, U> = Partial<UniqueObjectSlice<T, U>> & CommonObjectSlice<T, U>; 

我已將其附加到 function 只是為了檢查它是否正常工作 - 但只需為 class 子 myComponent ,您應該會得到預期的行為。

function myComponent<T extends PartialUnion<TvChannel, RadioChannel>>(properties: T) {
    // Unique keys
    type foo = typeof properties.foo; // string | undefined
    type subscribed = typeof properties.subscribed; // boolean | undefined

    // Common keys
    type id = typeof properties.id; // number
    type name = typeof properties.name; // string
}

游樂場鏈接

暫無
暫無

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

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