2017-09-29 1 views
2

Ich arbeite an der Verbesserung der Defs für Rosie, die derzeit sehr auf any verlassen und bieten nicht viel in Bezug auf die Sicherheit. Ich bin im Moment ein bisschen fest und könnte einen Ratschlag gebrauchen.TypeScript Generics und Funktionsargumente

Ich versuche, eine Signatur zu schreiben, das die folgenden zum Ausdruck bringt:

// 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>; 
} 

Eine Reihe von Tasten in der zweiten Argument angegeben wird. Die Werte davon werden als Argumente an die Funktion in der gleichen Reihenfolge übergeben. Ich will, um unnötige Art Abgüsse zu vermeiden, also sollten wir diese:

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};  
}); 

Der nächstgelegene ich bekommen kann, ist dies:

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>; 

zu 4 abhängige Werte abtippen, sondern nannte es bedarf der ausdrücklichen Abgüsse und Arten in der richtigen Reihenfolge nicht festgelegt:

// 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}`); 

Dies macht es mir möglich, die Reihenfolge der Abhängigkeiten zu ändern, ohne es zu zerbrechen, was nicht gut ist. Es gibt auch keinen Fehler, wenn ich mehr Argumente als abhängige Werte zur Verfügung stelle. Ich würde gerne einen Weg finden zum Ausdruck zu bringen "generatorFunction hat ein Argument für jedes Element in dependencies, vom Typ T[DependencyName]."

Ich hoffe, das macht Sinn. Schätze jede Hilfe, die jemand anbieten kann.

+0

Ich bin mir ziemlich sicher, dass es nicht möglich ist, es auf eine universelle Weise zu tun. Stattdessen sollten Sie separate Überladungen für 1,2,3, ... Parameter erstellen. Die maximale Anzahl sollte Ihren Anforderungen entsprechen. – MistyK

Antwort

2

Sie müssen Überladungen für jede Arity (Signatur) vornehmen. Nehmen wir zum Beispiel einen Blick auf wie Reselect Dinge tut

/* 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... 

Überlastungen Stellen für jede Anzahl von Argumenten, bis eine angemessene Anzahl (wie viele erwarten Sie? 4? 8?) Und Vergangenheit, die nur eine nicht-eingeschnürt verwenden generisch und lassen Sie den Benutzer es eingeben. Wenn Sie mehr als 8 Parameter haben, sollten Sie verletzen, um zu tippen.

+0

AH! RESELECT! Ich wusste, dass es ein "Irgendwo" in meiner App gab, wo ich dieses genaue Muster schön spielen sah, aber ich konnte mich einfach nicht erinnern, wo. Ich verwende Selektoren oft nicht genug. Vielen Dank! Das ist ausgezeichnet. Ich werde es am Montag versuchen, aber es ist das, worauf ich gehofft habe. – subvertallchris