2017-04-24 15 views
1

特定の条件に基づいて複数のメンバータイプを指定できますか? 他のメンバータイプに基づく条件付きメンバータイプ

  • value

    がタイプbooleanまたはDateであり、その後optionsタイプundefinedでなければなりません:私はあればあることを指定したい

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

    :たとえば、次の型を与えます。

  • valueを次にoptionsタイプstring[]でなければならないタイプstring又は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']; 
} 

は、明示的に

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

に動作しますが、コンパイラはその上のやるべきではない、明らかにStringOrStringArrayにキャスト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 
} 

これは間違いなく少し冗長ですが、お勧めの方法です。

関連する問題