2017-08-04 10 views
1

私は基本的なユニオンタイプを持っています。TypeScriptのユニオンタイプのリストからユニオンタイプを見つけて曖昧さを取り除く方法は?

type A = {type: "A"} 
    type B = {type: "B"} 
    type X = A | B 

と私は同じ型を持つリスト内の項目を見つける機能があります。

function find(x: X, list: Array<X>) { 
     return list.find(item => item.type === x.type) 
    } 

私は、この関数の戻り値の型が一致したXの特定のサブタイプであることを期待します入力x。つまり、find({type: "A"}, [{type: "A"}, {type: "B"}])はAのタイプを返すようにします。

どうすればいいですか?


編集:私が扱っていることはもう少し複雑です。私は、キューされているバッチの概念を持っていると私はそれが存在する場合、バッチにアイテムを追加したい、そう私は新しいバッチをエンキューしたい:

type A = { type: "A" } 
    type B = { type: "B" } 
    type X = A | B 

    type Batch<T extends X> = { type: T["type"]; batch: Array<T> } 
    type BatchA = Batch<A> 
    type BatchB = Batch<B> 
    type BatchTypes = BatchA | BatchB 

    function find(x: X, list: Array<BatchTypes>) { 
     return list.find(item => item.type === x.type) 
    } 

    function enqueue(x: X, queue: Array<BatchTypes>) { 
     const result = find(x, queue) 
     if (result) { 
      result.batch.push(x) 
     } else { 
      queue.push({type: x.type, batch:[x]}) 
     } 
    } 

    let a: A 
    let b: B 
    let queue: Array<BatchTypes> 

    enqueue(a, queue) 
    enqueue(b, queue) 

の労働組合を引き起こすので、ここでの問題はenqueueにあります両方のタイプ。私は種類をオーバーロードしようとすると、結果が適切に解決が、問題はfindの最初の引数でありますし、キューに新しいバッチを推進している。

function find(x: A, list: Array<BatchTypes>): BatchA 
    function find(x: B, list: Array<BatchTypes>): BatchB 
    function find(x: X, list: Array<BatchTypes>) { 
     return list.find(item => item.type === x.type) 
    } 

    function enqueue(x: A, queue: Array<BatchTypes>) 
    function enqueue(x: B, queue: Array<BatchTypes>) 
    function enqueue(x: X, queue: Array<BatchTypes>) { 
     const result = find(x, queue) 
     if (result) { 
      result.batch.push(x) 
     } else { 
      queue.push({ type: x.type, batch: [x] }) 
     } 
    } 

これを明確にする良い方法があります場合は私に知らせてください質問。 @のアルテムの答えを考える


、私は近い得ている:

function find<T extends X>(x: T, list: Array<BatchTypes>): Batch<T> { 
     return <Batch<T>>list.find(item => item.type === x.type) 
    } 

    function enqueue<T extends X>(x: T, queue: Array<BatchTypes>) { 
     const result = find(x, queue) 
     if (result) { 
      result.batch.push(x) 
     } else { 
      queue.push({ type: x.type, batch: [x] }) 
     } 
    } 

をしかし、問題はqueue.pushにまだあります。


多分これは、現在の問題を実証するより簡潔な例です。

type A = { type: "A" } 
    type B = { type: "B" } 
    type X = A | B 

    let list: Array<Array<A> | Array<B>> 

    function append<T extends X>(x: T) { 
     list.push([x]) 
    } 

    function append2(x: X) { 
     list.push([x]) 
    } 

答えて

1

あなたはfindためoverload declarationsを追加することによってそれを行うことができます。

type A = {type: "A"} 
type B = {type: "B"} 
type X = A | B 

function find(a: A, list: Array<X>): A; 
function find(a: B, list: Array<X>): B; 
function find(x: X, list: Array<X>) { 
    return list.find(item => item.type === x.type) 
} 

let a: A; 
let b: B; 
let x = [a, b]; 

let a1 = find(a, x); // inferred as A 
let b1 = find(b, x); // inferred as B 

find戻り値の型は、常にするかどうか最初の引数の型と同じであれば、反復を避けるために単一の汎用オーバーロード宣言を使用できます。

+0

興味深い。そのオーバーロードを行うために、Xのすべてのユニオンタイプを反復処理する方法はありますか? – Chet

+1

私は反復する方法はないと思っていますが、 'find'の戻り値の型と最初の引数の型が同じであることを表すために、単一の汎用宣言を使用することができます。私は答えを更新しました。 – artem

+0

私が追加した編集をチェックアウト - これはそこにある方法の一部です... – Chet

関連する問題