2016-04-12 13 views
0

erweitern Wenn Funktionalität in typescript mit anonymen Typen zum Beispiel wie folgt verketten:Wie anonymen Typ in Typoskript

let array = [{ seed: 2 }, { seed: 3 }]; 
    array 
    .map(i => ({ seed: i.seed, square: i.seed * i.seed })) 
    .forEach(i => console.log(`square for ${i.seed} is ${i.square}`)); 

ich neue anonymen Typ für Map-Funktion definieren müssen. Wenn ich mehrere Schritte hätte, die alle neue Eigenschaften erzeugen würden, würde ich am Ende viel Definitionscode schreiben, um alle Eigenschaften zu übernehmen. Ich könnte $.extend (oder Object.assign) verwenden, aber auf diese Weise werde ich Intellisense und starke Typisierung verlieren.

array 
    .map(i => $.extend(i, { square: i.seed * i.seed })) 
    .forEach(i => console.log(`square for ${i.seed} is ${i.square}`)); 

Wie kann ich anonyme Objekte erweitern, ohne alle Eigenschaften neu definieren zu müssen, während ich stark typisiere?

Antwort

1

ich gefunden habe, endlich eine Lösung. Dies kann durch Intersection Types erreicht werden. Diese können mit anonymen Typen und Klassen verwendet werden. Im folgenden Beispiel kopiert die extend-Funktion Eigenschaften von jedem Objekt und gibt ein Objekt des Schnitttyps zurück. Dies wird eine beträchtliche Menge an Typdefinitionscode reduzieren, ohne Intellisense und starke Typisierung zu verlieren.

function extend<T, U>(first: T, second: U): T & U { 
    let result = <T & U>{}; 
    for (let id in first) { 
     (<any>result)[id] = (<any>first)[id]; 
    } 
    for (let id in second) { 
     if (!result.hasOwnProperty(id)) { 
      (<any>result)[id] = (<any>second)[id]; 
     } 
    } 
    return result; 
} 

let array = [{ seed: 2 }, { seed: 3 }]; 

array 
    .map(i => extend(i, { square: i.seed * i.seed })) 
    .map(i => extend(i, { cube: i.square * i.seed })) 
    .forEach(i => console.log(`square for ${i.seed} is ${i.square} and cube is ${i.cube}`)); 

Same in Playground

Dies wird implementiert, F. E. in core-js und seine type definitions return Überschneidung Typ:

assign<T, U>(target: T, source: U): T & U; 
2

Wie wäre:

interface A { 
    seed: number; 
} 

interface B extends A { 
    square: number; 
} 

let array: A[] = [{ seed: 2 }, { seed: 3 }]; 
array 
    .map<B>(a => { 
     return { seed: a.seed, square: a.seed * a.seed } 
    }) 
    .forEach(b => console.log("square for ${b.seed} is ${b.square}")); 

oder (wenn Sie Dinge anonym bleiben wollen):

let array = [{ seed: 2 }, { seed: 3 }]; 
array 
    .map<{seed: number, square: number}>(a => { 
     return { seed: a.seed, square: a.seed * a.seed } 
    }) 
    .forEach(b => console.log("square for ${b.seed} is ${b.square}")); 

(verwenden Sie es in playground)

+0

Sie definieren noch Samen wieder in Rückgabewert. Wie wäre es, wenn es 5 Parameter gibt und map einen Parameter hinzufügt. Was für ein Durcheinander wäre das. –

+0

@JukkaVaris verwenden Sie also die erste Lösung mit den Schnittstellen. Es gibt keine Möglichkeit (das ist mir bewusst), es zu erweitern, sonst –

+0

Ich habe Angst davor. Mein tatsächlicher Anwendungsfall ist mit RxJS und dort können Ketten ziemlich lang sein. Interface Graph würde leicht aus der Hand wachsen. Ich verwende anonyme Typen, um die Menge an Code zu reduzieren, die ich schreiben muss, und ich würde gerne sehen, dass der Compiler Typen von der Verwendung ableiten kann. –

Verwandte Themen