2017-01-09 2 views
1

Was wäre der richtige/bevorzugte Weg, Flussanmerkungen zu einer Funktion wie dieser hinzuzufügen?Funktion, die einem Objekt eine Eigenschaft hinzufügt

function addBar(foo) { 
    foo.bar = 10 
    return foo 
} 

Lassen Sie uns sagen, dass ich die folgenden Typen haben:

type Foo = { foo: string } 
type FooBar = { foo: string, bar: number } 

und ich würde die Funktion in einem Foo nehmen möchten und eine FooBar zurück.

Bisher sind die besten Lösungen, die ich habe kommen mit sind dies:

function addBar(foo: Foo): FooBar { 
    const fooBar: FooBar = { ...foo, bar: 10 } 
    return fooBar 
} 

, die eine Kopie des Objekts erstellt und stützt sich auf die Erholung Eigenschaften. Oder das:

function addBar(foo: Foo): FooBar { 
    const fooBar: FooBar = (foo: any) 
    fooBar.bar = 10 
    return fooBar 
} 

, die einige hacky Casting erfordert.

In der Theorie sollte dies ohne Gießen oder Kopieren erreichbar sein. Kann die dynamische Analyse von Flow dies erkennen? Und sind andere Ansätze für diesen Anwendungsfall besser geeignet?

+1

Nun, Ändern des Typs eines vorhandenen Objekts durch Hinzufügen einer Eigenschaft * ist * hacky Casting. – Bergi

+3

Im Allgemeinen modelliert Flow die Nebenwirkungen von Funktionsaufrufen nicht. Es gibt also keine Möglichkeit zu verstehen, dass das Aufrufen einer Funktion das Objekt, das Sie haben, verändert. Sie haben richtig erkannt, dass Flow durch das Erstellen einer Kopie verstehen kann, was vor sich geht. Wenn Sie genau das tun, was Sie wollen, müssen Sie das Typsystem umgehen (was in einigen Fällen in Ordnung ist - es liegt wirklich an Ihnen). –

+0

Hmm, gute Punkte ... es erschien mir zunächst nicht hacky, weil ich es wahrscheinlich als eine Umwandlung dachte. Aber jetzt, wo ich daran denke, macht das Erstellen einer Kopie des Objekts Sinn, wenn es eine Umwandlung ist :) – mjomble

Antwort

0

Ihr Problem ist mit dem foo Objektliteral, das keine zusätzlichen Mutationen unterstützt, wenn es nicht speziell gekennzeichnet ist.

Ihrem Beispiel zu vereinfachen, noch weiter, würde die folgenden ein Fluss Fehler werfen:

const hello = { hello: 'hello' }; 
hello.world = 'world'; 

18: hello.world = 'world'; 
     ^property `world`. Property not found in 
18: hello.world = 'world'; 
    ^object literal 

Allerdings würde die folgende nicht:

const hello: { hello: 'hello', [someOtherKey: string]: mixed }; 
hello.world = 'world'; 

// no errors! 

jedoch, so dass "property variance" effektiv hello entsiegelt und verwandelt es in eine Map, die zu Silent-Typ-Fehlern geöffnet wird, wenn Sie nicht möchten, dass eine Eigenschaft hinzugefügt wird.

Eine weitere einfache Möglichkeit, Ihre Methode zu annotieren wäre folgendes zu tun:

type FooBarType = { 
    foo: mixed, 
    bar?: number 
} 

function addBar(foo: FooBarType): FooBarType { 
    foo.bar = 10; 
    return foo; 
} 

addBar({ foo: 'hello' }); // no errors! 

Dies stellt sicher, dass die Art der foo unterstützen kann mit Bar hinzugefügt. Dies ist nicht das Gleiche wie tatsächlich die Eigenschaft. Im Allgemeinen möchten Sie nicht, dass Ihre Methoden Objekttypen umgehen, um ihre Eigenschaften zu ändern. Definieren Sie das Objekt vielmehr so, dass es die Mutationen unterstützen kann. Andernfalls verwenden Sie einen funktionalen Ansatz und geben ein neues Objekt zurück. Das Folgende würde Ihnen erlauben, foo versiegelt zu halten:

+0

Gute Punkte und die funktionale Annäherung würde wahrscheinlich am besten zu meinem Anwendungsfall passen. Das Beispiel mit FooBarType scheint jedoch nicht fehlerfrei zu sein: https: // flowtype.org/try/# 0C4TwDgpgBAYg9nAQgQwE4BVzQLxQN4BQUUAZggFxQC2AlgB4QAmANEVAEZqUB2ArlewioCAXwIESvbgGNgNONyjJGjFKgAUZOJXhI0mSAEodCNQeiFiWgHSdUUXAEYADAG42qCMF6pFW92IEyqpo6nikFFAA5AAWEAA28XBRUCKGQA – mjomble

+0

sorry, ich diese Bar vergessen haben, optional sein musste. https://flowtype.org/try/#0C4TwDgpgBAYg9nAQgQwE4BVzQLxQN4BQUUAZggFxQC2AlgB4QAmANEVAEZoD8lAdgK5V2EVAQC+BAiX68AxsBpxeUZI0YpUACjJxK8JGkyQAlHoQaj0QsR0A6Tqii4AjAAYA3G1QRg-VMp1PCQJVdTRNPFIKKAByAAsIABtEuBioMWMgA – thejohnbackes

Verwandte Themen