2015-08-17 47 views
1

所以,我想創建一個negate函數,它需要一些函數返回一些參數列表的布爾值,然後返回一個採用相同參數併產生完全相反布爾結果的函數。函數使用謂詞函數(返回一個布爾值),並返回一個具有相同參數的謂詞函數

這是可能的,如果我們被淘汰離開類型安全:

function negate(predicate: Function): Function { 
    return function() { 
     return !predicate.apply(this, arguments); 
    } 
} 

我們甚至可以表明,所得到的函數使用() => boolean返回類型返回boolean。但是這個簽名表明返回的函數沒有參數 - 實際上,它應該獲得與在函數中傳遞的參數完全相同的參數。

我希望能夠指定這一點。如果我限制predicate正好一個參數,我可以:

function negate<A>(predicate: (a: A) => boolean): (a: A) => boolean { 
    return function (a: A) { 
     return !predicate.apply(this, arguments); 
    } 
} 

而且我可以用重載來指定這個零,一,二,等參數,通過手動定義每個版本。在某些時候,我將能夠接受與任何功能應合理採用的參數一樣多的參數。並擴展它與更多的參數,如果我的定義「合理」擴大,不是很可能很多工作。

另外,this answer提出不同的策略:

export function negate<Predicate extends Function>(p: Predicate): Predicate { 
    return <any> function() { 
     !p.apply(this, arguments); 
    } 
} 

,只要謂詞實際上沒有返回一個布爾這是類型安全的,但沒有限制參數事物的方式對返回boolean(更糟的是,這會默默地將任何非布爾結果轉換爲布爾值,以便應用!,並且這不會在返回的函數的簽名中指示)。

所以,我真的很想都是完全類型安全幹。

Typescript是否有任何功能可以使這成爲可能?

+0

@basarat雖然相似,我不認爲這是一個*重複*的問題,因爲這裏的要求,即傳入的函數返回'boolean'。編輯標題專注於此。 – KRyan

回答

0

想通了一個辦法。

interface IPredicate { 
    (...args: any[]): boolean; 
} 
function negate<Predicate extends IPredicate>(p: Predicate): Predicate { 
    return <any> function(): boolean { 
     return !p.apply(this, arguments); 
    } 
} 

IPredicate接口允許我們定義,無論我們採取的論點,我們期待一個布爾結果,然後使用<Predicate extends IPredicate>允許我們定義的參數p和恢復功能都採取同樣的參數,因爲他們必須是相同Predicateextends IPredicate。我們使用的是apply,所以類型信息丟失了。因此<any>用於基本保證TypeScript編譯器的內部函數是正確的。這使內部非類型安全,但它很小,不需要維護一次寫入。

這也可以被擴展以處理謂詞上的其他邏輯功能,例如,union

export function union<Predicate extends IPredicate>(
    p: Predicate, 
    ...rest: Predicate[] 
): Predicate { 
    if (rest.length > 0) { 
     return <any> function() { 
      return p.apply(this, arguments) || union.apply(this, rest).apply(this, arguments); 
     } 
    } 
    else { 
     return p; 
    } 
} 
相關問題