Typescript: Vorschlag: Der primitive Typ "Objekt"

Erstellt am 26. Jan. 2015  ·  17Kommentare  ·  Quelle: microsoft/TypeScript

Der primitive Typ object

Dieser Vorschlag beschreibt einen neuen primitiven Typ für Typoskript object .

Anwendungsfall

Die JavaScript-Kern-API enthält einige Funktionen, die object als Parameter verwenden:

  • Object.getPrototypeOf
  • Object.getOwnPropertyDescriptor
  • Object.create
  • ...usw

Derzeit gibt es in Typoskript keine Möglichkeit zu verhindern, dass andere primitive Typen ( string , number usw.) an diese Funktionen übergeben werden.
Zum Beispiel ist Object.create('string') eine perfekt gültige Typoskript-Anweisung, auch wenn sie einen Fehler enthält.
Das Erstellen eines neuen primitiven Typs object würde es ermöglichen, die Signatur dieser Funktion und jeder Funktion, die ähnliche Einschränkungen aufweist, korrekter zu modellieren.

Typprüfung

Zuweisbarkeit

Der Typ object entspricht {} abzüglich der Zuweisbarkeit eines anderen Basistyps. Dies bedeutet:

  • Alle anderen Grundtypen können nicht object
  • Jeder nicht grundlegende Typ kann object
  • Das Objekt kann nur {} und any

Dieses Verhalten stimmt mit der Funktionsweise von Javascript überein. Der Typ repräsentiert jeden Wert, der die Einschränkung typeof value === 'object' plus undefined berücksichtigt.

Typ Wache

Für object ein neuer Typschutz eingeführt werden: typeof value === 'object' .
Optional kann der Compiler auch einen Vergleich mit der Funktionsbesetzung Object akzeptieren: Object(value) === value .

Suggestion help wanted

Hilfreichster Kommentar

+1 zu diesem Vorschlag. Ich würde WeakMap als "Experten" -API betrachten, aber ich halte es allein für Grund genug, dies zu implementieren. Da die Laufzeit zwischen Objekttypen und primitiven Typen unterscheidet, ist es nur sinnvoll, in TypeScript eine Funktion zu haben, um auch die Unterscheidung zu treffen.

Dieser Vorschlag wird auch das Problem der Eingabe von "Objekttaschen" lösen, bei denen jede Eigenschaft optional ist, andere primitive Typen jedoch nicht zulässig sind.

Alle 17 Kommentare

Es wäre nützlich, einige andere APIs als die Object. -Funktionen aufzulisten, die davon profitieren würden.

In der Javascript-Kern-API außer Object profitieren möglicherweise nur einige es6-Konstrukte davon (WeakMap, Proxy usw.).
Zum Beispiel würde jede Unterstrichsammlungsfunktion auch eine bessere Typisierung erhalten. Framework wie React verwenden eine 'setState'-Methode, die nur Objekte oder null , ImmutableJS, Mori usw. usw. akzeptiert.

Bearbeiten: Unterstreichen Sie die Sammlungsarbeit mit beliebigen Typen

Besprochen bei der Besprechung zur Überprüfung von Vorschlägen. Dies alles macht Sinn, aber wir müssen die Komplexität eines neuen primitiven Typs mit der Anzahl der Fehler / der Fülle der Beschreibung, die er liefern kann, rechtfertigen. Grundsätzlich mehr Beispiele für APIs, die nicht mit Grundelementen arbeiten können, insbesondere solche, die keine "Experten" -APIs sind (z. B. Proxies).

Mehr als Referenz als Empfehlung posten: zwinker:

interface String { _primitiveBrand?: string; }
interface Boolean { _primitiveBrand?: boolean; }
interface Number { _primitiveBrand?: number; }

interface ObjectOnly {  _primitiveBrand?: void; }

function fn(x: ObjectOnly) { }

// Error
fn(43);
// Error
fn('foo');
// OK
fn({});
// OK
fn(window);

+1 zu diesem Vorschlag. Ich würde WeakMap als "Experten" -API betrachten, aber ich halte es allein für Grund genug, dies zu implementieren. Da die Laufzeit zwischen Objekttypen und primitiven Typen unterscheidet, ist es nur sinnvoll, in TypeScript eine Funktion zu haben, um auch die Unterscheidung zu treffen.

Dieser Vorschlag wird auch das Problem der Eingabe von "Objekttaschen" lösen, bei denen jede Eigenschaft optional ist, andere primitive Typen jedoch nicht zulässig sind.

Object.observe erfordert ebenfalls ein nicht primitives Ziel: http://arv.github.io/ecmascript-object-observe/#Object.observe

Ich denke, der Titel ist etwas verwirrend, da er das Wort "primitiv" erwähnt. Dies könnte alternativ als _ "ECMAScript-Objekttyp" _ oder _ "Laufzeitobjekttyp" _ bezeichnet werden. Welche von anderen als primitiven Typen (einschließlich undefined Typ und Symbolen), Funktions- oder Konstruktortypen zuweisbar wären. Die Kriterien für einen legalen object -Typ sollten auf dem folgenden Schutz basieren:

let isObject (x) => typeof x === "object";

Laut MDN ist dies die Ausgabe von typeof :

Undefiniert : "undefiniert"
Null : "Objekt" (siehe unten)
Boolean : "Boolean"
Nummer : "Nummer"
String : "string"
Symbol (neu in ECMAScript 2015) : "Symbol"
Hostobjekt (von der JS-Umgebung bereitgestellt) : Implementierungsabhängig
Funktionsobjekt (implementiert [[Aufruf]] in ECMA-262-Begriffen) : "Funktion"
Jedes andere Objekt : "Objekt"

Ohne diesen Typ gibt es keine Möglichkeit, einen genauen Typ für den oben genannten Schutz korrekt zuzuordnen, auch nicht als benutzerdefinierten Schutz. Dies ist auch wichtig für die Verwendung mit Funktionen, für die ausschließlich ein Objekt erforderlich ist, das Eigenschaften aufweist und for in Schleifen und Aufrufe des Prototyps Object zulässt, sowie für die Implementierung allgemeiner Einschränkungen wie T extends object und dann sicher auf Eigenschaften verweisen oder die Prototypfunktionen verwenden.

Das Ausschließen von Funktionen und Konstruktoren wäre jedoch in einigen Fällen etwas einschränkend, sodass es einen anderen Typ geben könnte, der sie ebenfalls einschließt und als "nicht-primitiver Objekttyp" bezeichnet wird. Eine teilweise Problemumgehung könnte die Gewerkschaft object | Function obwohl Abgüsse oder zusätzliche Wachen erforderlich wären, um richtig damit umzugehen.

PRs akzeptieren. Dies scheint ein häufiges Problem zu sein. Dies wird eine bahnbrechende Veränderung für jeden sein, der mutig genug ist, interface object { ... } geschrieben zu haben. Die Implementierung sollte unkompliziert sein und den oben beschriebenen Regeln folgen.

Randnotiz: Wir fragen uns alle, wo @fdecampredon gewesen ist!

@ RyanCavanaugh Wechsel der Arbeitsstadt und leider nicht viel Typoskript in meinem neuen Job: D.

Großartig. Ich möchte diesen Typ in TS1.8 verwenden.

Ich würde auch gerne so etwas wie einen object Typ sehen. Ich frage mich jedoch, ob es typeof value === 'object' , da dies Funktionen ausschließen würde. Stattdessen scheint es mir , dass die prospektive object sollte Art den Objekt reflektiert Sprachtyp , die Funktionen enthält. Dafür gibt es einige Gründe:

  • APIs, die meines Wissens immer einfache Objekte akzeptieren, akzeptieren auch Funktionen.
  • Funktionen erben vom Konstruktor Object .

Ich werde diese in Ordnung bringen.

APIs

APIs wie WeakMap , die nur Objekte verwenden, akzeptieren den Objektsprachentyp, nicht nur einfache Objekte. Folgendes ist in Ordnung:

function theAnswer() {}

let map = new WeakMap();

map.set(theAnswer, 42);
console.log(map.get(theAnswer)); // 42

Dies gilt für benutzerdefinierte APIs ebenso wie für integrierte APIs. Wenn ich ein Objekt erwarte, möchte ich normalerweise nur ein Bündel von Eigenschaften. Funktionen sind nur aufrufbare Bündel von Eigenschaften.

Erbe

Da Function den Konstruktor Object , können wir die statischen und Instanzmethoden, die für Object verfügbar sind, auch für Funktionen verwenden. Zum Beispiel ist Folgendes möglich:

class DeepThought {
  static getAnswer() {
    return 42;
  }
}

let computer = Object.create(DeepThought);

console.log(computer.getAnswer()); // 42
console.log(Object.getPrototypeOf(computer)); // [Function: DeepThought]

Das obige Beispiel ist zwar etwas albern, zeigt jedoch nur, dass APIs, die intern die Methoden Object verwenden, genauso gut Funktionen akzeptieren können.

Daher würde ich vorschlagen, dass der Typ object dem folgenden entspricht, der dem Typ der Objektsprache entspricht (außer dass er null , aber es gibt keinen Schutz gegen null in TypeScript auf jeden Fall).

function isObject(value) {
  return typeof value === 'object' || typeof value === 'function';
}

Anwendungsfall

Ich habe ein Projekt namens Deep Map , das die Schlüssel-Wert-Paare verschachtelter Objekte durchläuft und dabei primitive Werte transformiert. Als solches unterscheidet es zwischen primitiven und nicht-primitiven Typen. Ich musste eine benutzerdefinierte NonPrimitive -Schnittstelle wie folgt definieren:

interface NonPrimitive {
  [key: string]: any;
  [index: number]: any;
}

export class DeepMap {
  // ...
  private mapObject(obj: NonPrimitive): NonPrimitive { /* ... */ }
}

Dies ist nicht das erste Mal, dass ich die Schnittstelle NonPrimitive definieren musste. Es wäre schön, wenn ich das einfach machen könnte:

export class DeepMap {
  // ...
  private mapObject(obj: object): object { /* ... */ }
}

Wie ich oben angedeutet habe, ist es mir egal, ob der Parameter obj aufrufbar ist oder nicht. Alles, was zählt, ist, dass es sich um den Sprachtyp Object _ handelt, dh um ein Bündel von Eigenschaften, deren Schlüssel-Wert-Paare ich durchlaufen kann.

Ich würde zustimmen, dass Funktionen object s sind. Die Absicht ist, Primitive auszuschließen.

Ok, ich dachte, das muss die Absicht gewesen sein. Ich dachte nur, vielleicht fehlt mir bei all dem Gerede von typeof value === 'object' .

Würde dieser object -Typ eine Ad-hoc-Eigenschaftszuweisung ermöglichen (wie any )? Zum Beispiel:

const foo: object = {};

foo.bar = 'baz';

Nein

Was ist der praktische Unterschied zwischen

export class DeepMap {
  // ...
  private mapObject(obj: object): object { /* ... */ }
}

und

export class DeepMap {
  // ...
  private mapObject(obj: Object): Object { /* ... */ }
}

? (Verwenden von object vs Object ). Es scheint mir, dass sich ein Function von Object , also verstehe ich nicht, warum wir das nicht schon tun können. Können Sie erklären?

@trusktr Alle anderen Werte als null und undefined dem Typ Object zugewiesen werden. Eine Funktion, die ein Object akzeptiert, akzeptiert eine Zeichenfolge, eine Zahl, einen Booleschen object zugewiesen werden. Das Übergeben einer Zeichenfolge usw. führt zu einem Fehler bei der Kompilierung. Der Typ object ist nützlich, wenn wir einen nicht primitiven Wert erwarten, es uns aber egal ist, welche Eigenschaften er hat.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen