2017-04-24 146 views
1

是否可以根據特定條件指定多個可能的成員類型?例如,給予以下類型:基於其他成員類型的條件成員類型

interface DataItem { 
    value: boolean | Date | string | string[]; 
    options: undefined | string[]; 
} 

我想說明,如果:

  • valueboolean類型或Date的那麼options必須undefined類型。
  • valuestring型或string[]的然後options必須string[]類型。

有沒有辦法在當前版本的TypeScript(2.2)中指定上述約束?此外,如果是那麼我假設一個部件上添加型後衛應該適用於其他成員,即:

let data: DataItem; 
if (typeof data.value === 'boolean') { 
    data.options = ['a']; // => Error Type 'string[]' is not assignable to type 'undefined'. 
} 

我嘗試以下,但沒有奏效:

interface BooleanOrDateItem { 
    value: boolean | Date; 
} 

interface StringOrStringArrayDataItem { 
    value: string | string[]; 
    options: string[]; 
} 

type DataItem = BooleanOrDateItem | StringOrStringArrayDataItem; 

let data: DataItem; 

if (typeof data.value === 'string') { 
    // I would expect this to work but the compiler complains 
    // => Property 'options' does not exist on type 'DataItem'. 
    //   Property 'options' does not exist on type 'BooleanOrDateItem'. 
    data.options = ['a']; 
} 

明確鑄造StringOrStringArray明顯作品

if (typeof data.value === 'string') { 
    (<StringOrStringArrayDataItem>data).options = ['a']; 
} 

但不應編譯器做的我的代表,因爲它有足夠的信息來推斷dataStringOrStringArrayDataItem

+0

我覺得這種方法是行不通的,我會使用'任何'數據類型或創建多個接口,並找出你需要使用工廠。 –

回答

1

我相信你正在尋找User-defined Type Guards。在每個if語句之後,如果返回值爲true,TypeScript會將dataItem的類型縮小爲正確的類型。

interface DataItem { 
    value: boolean | Date | string | string[]; 
    options: undefined | string[]; 
} 

interface BoolOrDateDataItem extends DataItem { 
    value: boolean | Date; 
    options: undefined; 
} 
interface StringDataItem extends DataItem { 
    value: string | string[]; 
    options: string[]; 
} 

function isBoolOrDateDataItem(dataItem: DataItem): dataItem is BoolOrDateDataItem { 
    return typeof dataItem.value === 'boolean' || dataItem.value instanceof Date; 
} 

function isStringDataItem(dataItem: DataItem): dataItem is StringDataItem { 
    return typeof dataItem.value === 'string' || dataItem.value instanceof Array; 
} 

let dataItem: DataItem = { 
    value: true, 
    options: undefined 
} // Or whatever it may be 

if (isStringDataItem(dataItem)) { 
    dataItem.value = new Date(); // TypeScript warns value must be string | string[] - knows it is a StringDataItem here 
} else if (isBoolOrDateDataItem(dataItem)) { 
    dataItem.value = true; // No error 
} 

這絕對有點冗長,但似乎是推薦的做事方式。