Bauen Sie ein Funktionsobjekt mit Eigenschaften in Typoskript

stimmen
46

Ich möchte eine Funktion Objekt erstellen, die auch einige Eigenschaften auf sie gehalten hat. Zum Beispiel in JavaScript würde ich tun:

var f = function() { }
f.someValue = 3;

Jetzt in Typoskript kann ich den Typ dieses wie beschreiben:

var f: { (): any; someValue: number; };

Allerdings kann ich nicht wirklich bauen, ohne eine Besetzung zu erfordern. Sowie:

var f: { (): any; someValue: number; } =
    <{ (): any; someValue: number; }>(
        function() { }
    );
f.someValue = 3;

Wie würden Sie diese ohne Guss bauen?

Veröffentlicht am 07/10/2012 um 07:08
quelle vom benutzer
In anderen Sprachen...                            


9 antworten

stimmen
73

Update: Diese Antwort war die beste Lösung in früheren Versionen von Typoskript, aber es gibt bessere Optionen in neueren Versionen (siehe andere Antworten).

Die akzeptierte Antwort funktioniert und könnte in einigen Situationen erforderlich sein, hat aber den Nachteil keine Typsicherheit geschaffen wird, das Objekt aufzubauen. Diese Technik wird mindestens eine Art Fehler auslösen, wenn Sie eine nicht definierte Eigenschaft hinzuzufügen versuchen.

interface F { (): any; someValue: number; }

var f = <F>function () { }
f.someValue = 3

// type error
f.notDeclard = 3
Beantwortet am 05/09/2013 um 16:12
quelle vom benutzer

stimmen
34

Maschinenschrift soll durch diesen Fall behandeln Erklärung Verschmelzen :

Sie können auch mit JavaScript Praxis der Schaffung einer Funktion und dann zur Verlängerung der Funktion weiter durch Hinzufügen von Eigenschaften auf die Funktion vertraut sein. Typoskript verwendet Erklärung Verschmelzung wie diese aufzubauen Definitionen in einer typsichere Weise.

Erklärung Verschmelzung lässt uns sagen, dass etwas ist sowohl eine Funktion und ein Namensraum (internes Modul):

function f() { }
namespace f {
    export var someValue = 3;
}

Auf diese Weise bleibt die Eingabe und lässt uns beide schreiben f()und f.someValue. Wenn eine .d.tsSchreibdatei für bestehende JavaScript - Code verwenden declare:

declare function f(): void;
declare namespace f {
    export var someValue: number;
}

Hinzufügen von Eigenschaften zu Funktionen ist oft ein verwirrendes oder unerwartete Muster in Typoskript, so versuchen Sie es zu vermeiden, aber es kann notwendig sein, bei der Verwendung oder Umwandlung von älterem JS-Code. Dies ist eines der wenigen Male, es wäre angebracht interne Module (Namespaces) mit externem zu mischen.

Beantwortet am 28/10/2015 um 13:47
quelle vom benutzer

stimmen
27

Dies ist leicht erreichbar jetzt (Typoskript 2.x) mit Object.assign(target, source)

Beispiel:

Geben Sie hier image description

Die Magie ist hier, dass Object.assign<T, U>(...)typisiert ist eine Rückkehr Kreuzung Typ T & U.

Erzwingen, dass dies zu einer bekannten Schnittstelle löst auch straight-forward:

interface Foo {
  (a: number, b: string): string[];
  foo: string;
}

let method: Foo = Object.assign(
  (a: number, b: string) => { return a * a; },
  { foo: 10 }
); 

Fehler: foo: Zahl nicht zuordenbar foo: string
Fehler: Anzahl nicht zuordenbar string [] (Rückgabetyp)

Nachteil: Sie müssen möglicherweise POLYfill wenn Targeting älteren Browser Object.assign.

Beantwortet am 25/01/2017 um 13:43
quelle vom benutzer

stimmen
17

Wenn also die Voraussetzung, um diese Funktion einfach erstellen und zuweisen zu „f“ ohne Besetzung, ist hier eine mögliche Lösung:

var f: { (): any; someValue: number; };

f = (() => {
    var _f : any = function () { };
    _f.someValue = 3;
    return _f;
})();

Im Wesentlichen ist es verwendet eine selbst Ausführung Funktionsliteral zu „konstruieren“, ein Objekt, das diese Signatur wird übereinstimmen, bevor die Zuordnung erfolgt. Die einzige Merkwürdigkeit ist, dass die innere Deklaration der Funktion des Typs sein muss ‚any‘, andernfalls wird der Compiler schreit, dass Sie auf eine Eigenschaft sind zuweisen, die noch auf dem Objekt nicht existiert.

EDIT: der Code ein wenig vereinfacht.

Beantwortet am 07/10/2012 um 17:33
quelle vom benutzer

stimmen
1

Ich kann nicht sagen, dass es sehr einfach ist, aber es ist auf jeden Fall möglich:

interface Optional {
  <T>(value?: T): OptionalMonad<T>;
  empty(): OptionalMonad<any>;
}

const Optional = (<T>(value?: T) => OptionalCreator(value)) as Optional;
Optional.empty = () => OptionalCreator();

Wenn Sie neugierig geworden ist dies aus einem Kern von mir mit dem Typoskript / JavaScript - VersionOptional

Beantwortet am 07/02/2018 um 23:57
quelle vom benutzer

stimmen
1

Eine aktualisierte Antwort: da die Zugabe von Kreuzungstypen über &, ist es möglich, zwei abgeleitete Typen on the fly „verschmelzen“.

Hier ist ein allgemeiner Helfer, die die Eigenschaften eines Objekts liest fromund kopiert sie auf ein Objekt onto. Es gibt das gleiche Objekt , ontoaber mit einer neuen Art , die beiden Arten von Eigenschaften enthalten, so richtig das Laufzeitverhalten beschreiben:

function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
    Object.keys(from).forEach(key => onto[key] = from[key]);
    return onto as T1 & T2;
}

Diese Low-Level-Helfer nicht durchführt noch eine Art Behauptung, aber es ist typsicher durch Design. Mit diesem Helfer an Ort und Stelle haben wir einen Operator, dass wir die OP das Problem zu lösen, mit voller Typsicherheit verwenden:

interface Foo {
    (message: string): void;
    bar(count: number): void;
}

const foo: Foo = merge(
    (message: string) => console.log(`message is ${message}`), {
        bar(count: number) {
            console.log(`bar was passed ${count}`)
        }
    }
);

Klicken Sie hier , um es auszuprobieren im Typoskript Spielplatz . Beachten Sie, dass wir gezwungen foovom Typ zu sein Foo, so das Ergebnis mergehat eine vollständig zu sein Foo. Also , wenn Sie umbenennen , barum baddann erhalten Sie einen Typfehler.

NB Es gibt immer noch eine Art Loch hier jedoch. Typoskript bietet keine Möglichkeit , einen Typ - Parameter zu beschränken „keine Funktion“ zu sein. So könnten Sie verwirren und Ihre Funktion als zweites Argument übergeben zu merge, und das würde nicht funktionieren. Also , bis diese deklariert werden können, müssen wir es zur Laufzeit fangen:

function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
    if (typeof from !== "object" || from instanceof Array) {
        throw new Error("merge: 'from' must be an ordinary object");
    }
    Object.keys(from).forEach(key => onto[key] = from[key]);
    return onto as T1 & T2;
}
Beantwortet am 10/03/2016 um 19:14
quelle vom benutzer

stimmen
1

Als Abkürzung können Sie dynamisch den Objektwert mit dem [ ‚Eigentum‘] Accessor zuordnen:

var f = function() { }
f['someValue'] = 3;

Dies umgeht die Typprüfung. Es ist jedoch ziemlich sicher, weil Sie absichtlich haben, um die Eigenschaft Zugriff auf die gleiche Art und Weise:

var val = f.someValue; // This won't work
var val = f['someValue']; // Yeah, I meant to do that

Wenn Sie jedoch wirklich die Art Prüfung für den Eigenschaftswert wollen, wird dies nicht funktionieren.

Beantwortet am 11/10/2012 um 05:38
quelle vom benutzer

stimmen
0

Alte Frage, aber für die Versionen von Typoskript mit 3.1 starten, können Sie einfach tun , um die Eigenschaftszuweisung , wie Sie es im Klar JS, solange Sie eine Funktionsdeklaration oder die Verwendung constSchlüsselwort für die Variable:

function f () {}
f.someValue = 3; // fine
const g = function () {};
g.someValue = 3; // also fine
var h = function () {};
h.someValue = 3; // Error: "Property 'someValue' does not exist on type '() => void'"

Referenz und Online - Beispiel .

Beantwortet am 26/11/2018 um 21:38
quelle vom benutzer

stimmen
0

Dies weicht von der starken Typisierung, aber Sie tun können,

var f: any = function() { }
f.someValue = 3;

wenn Sie versuchen, um drückend starke Typisierung zu bekommen wie ich war, als ich diese Frage gefunden. Leider ist dies ein Fall, Typoskript auf absolut gültige JavaScript versagt, so dass Sie müssen Sie Typoskript sagen sich zurückzuziehen.

„Du JavaScript ist absolut gültige Typoskript“ das Ergebnis falsch. (Anmerkung: Die Verwendung 0,95)

Beantwortet am 21/02/2014 um 16:59
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more