2017-08-04 31 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

你可以通過添加overload declarationsfind

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返回類型永遠與第一個參數的類型相同,可以使用單個泛型重載聲明來避免重複:

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

有趣。是否有任何方法遍歷X中的所有聯合類型來執行重載? – Chet

+1

我不認爲有一種方法可以迭代,但是您可以使用單個泛型聲明來表示'find'返回類型和第一個參數類型是相同的。我更新了答案。 – artem

+0

查看我剛剛添加的編輯 - 事實證明這只是這種方式的一部分... – Chet

相關問題