2017-09-29 64 views
2

我正在努力改進Rosie的defs,它目前在any上依賴很多,並且不提供很多安全方面的東西。我現在有點卡住了,可以使用一些建議。TypeScript泛型和函數參數

我想寫表達了以下的簽名:

// this is invalid, but something like this is the goal 
interface IFactory<T = any> { 
    attr<K extends keyof T, D extends keyof T>(name: K, dependencies: D[], generatorFunction: (value1?: D[0], value2?: D[1], value3?: D[2]), value4?: D[3] => T[K]): IFactory<T>; 
} 

鍵的數組中的第二個參數中給出。這些值以參數的形式作爲參數傳遞給函數。我希望避免不必要的類型轉換,所以我們應該得到這樣的:

Factory.define<Person>('Person').attr('fullName', ['firstName', 'lastName', 'age'], (firstName, lastName, age) => { 
    // it knows that firstName is a string, lastName is a string, age is a number 

    if (age > 10) { 
    // this will error 
    return age; 
    } 

    return `${firstName} ${lastName};  
}); 

我能得到的最接近的是這樣的:

attr<K extends keyof T, D extends keyof T>(name: K, dependencies: D[], generatorFunction: (value1: T[D], value2: T[D], value3: T[D], value4: T[D]) => T[K]): IFactory<T>; 

這將類型多達4個相關的值,但稱這是需要明確的管型和不正確的順序設置類型:

// it knows that each of the three arguments are string | number 
existingDefinition.attr('fullName', ['firstName', 'lastName', 'age'], (firstName: string, lastName: string, age: number) => `${firstName} ${lastName}`); 

這可以爲我改變依賴的順序沒有它打破,這也是白搭。如果我提供比依賴值更多的參數,它也不會產生錯誤。我想找到一種表達「generatorFunction」的方法,其中dependencies中的每個元素都有一個參數,T[DependencyName]

我希望這是有道理的。欣賞任何人可以提供的幫助。

+0

我很確定這是不可能以通用的方式來完成的。相反,您應該爲1,2,3,...參數創建單獨的重載。最大數量應該符合您的需求。 – MistyK

回答

2

您需要爲每個元素(簽名)重載。例如,看看Reselect如何做的事情

/* one selector */ 
export function createSelector<S, R1, T>(
    selector: Selector<S, R1>, 
    combiner: (res: R1) => T, 
): OutputSelector<S, T, (res: R1) => T>; 
export function createSelector<S, P, R1, T>(
    selector: ParametricSelector<S, P, R1>, 
    combiner: (res: R1) => T, 
): OutputParametricSelector<S, P, T, (res: R1) => T>; 

/* two selectors */ 
export function createSelector<S, R1, R2, T>(
    selector1: Selector<S, R1>, 
    selector2: Selector<S, R2>, 
    combiner: (res1: R1, res2: R2) => T, 
): OutputSelector<S, T, (res1: R1, res2: R2) => T>; 
export function createSelector<S, P, R1, R2, T>(
    selector1: ParametricSelector<S, P, R1>, 
    selector2: ParametricSelector<S, P, R2>, 
    combiner: (res1: R1, res2: R2) => T, 
): OutputParametricSelector<S, P, T, (res1: R1, res2: R2) => T>; 

/* three selectors */ 
export function createSelector<S, R1, R2, R3, T>(
    selector1: Selector<S, R1>, 
    selector2: Selector<S, R2>, 
    selector3: Selector<S, R3>, 
    combiner: (res1: R1, res2: R2, res3: R3) => T, 
): OutputSelector<S, T, (res1: R1, res2: R2, res3: R3) => T>; 
export function createSelector<S, P, R1, R2, R3, T>(
    selector1: ParametricSelector<S, P, R1>, 
    selector2: ParametricSelector<S, P, R2>, 
    selector3: ParametricSelector<S, P, R3>, 
    combiner: (res1: R1, res2: R2, res3: R3) => T, 
): OutputParametricSelector<S, P, T, (res1: R1, res2: R2, res3: R3) => T>; 

// etc... 

作出的論據每個號碼重載,直到一個合理的數字(有多少是你期待?4?8?)和過去那種只使用非收縮通用並讓用戶輸入它。如果你有超過8個參數,應該傷害你輸入。

+0

啊!重新選擇!我知道在我的應用程序中有_somewhere_,我發現這個確切的模式非常漂亮,但我不記得在哪裏。我不經常使用選擇器。謝謝!這很好。星期一我會給你一個鏡頭,但這正是我所希望的。 – subvertallchris