Wie ordne ich einem Objekt in TypeScript dynamisch Eigenschaften zu?


359

Wenn ich einem Objekt in Javascript programmgesteuert eine Eigenschaft zuweisen möchte, würde ich dies folgendermaßen tun:

var obj = {};
obj.prop = "value";

In TypeScript wird jedoch ein Fehler generiert:

Die Eigenschaft 'prop' existiert nicht für den Wert vom Typ '{}'

Wie soll ich einem Objekt in TypeScript eine neue Eigenschaft zuweisen?


1
Zu Ihrer Information. Ich habe eine diesbezügliche Diskussion eröffnet , wenn Sie ihr folgen möchten.
Joshuapoehls

Antworten:


456

Es ist möglich, objals zu bezeichnen any, aber das macht den ganzen Zweck der Verwendung von Typoskript zunichte. obj = {}impliziert objist ein Object. Es anymacht keinen Sinn, es als zu markieren. Um die gewünschte Konsistenz zu erreichen, könnte eine Schnittstelle wie folgt definiert werden.

interface LooseObject {
    [key: string]: any
}

var obj: LooseObject = {};

ODER um es kompakt zu machen:

var obj: {[k: string]: any} = {};

LooseObjectkann Felder mit einer beliebigen Zeichenfolge als Schlüssel akzeptieren und anyals Wert eingeben.

obj.prop = "value";
obj.prop2 = 88;

Die wahre Eleganz dieser Lösung besteht darin, dass Sie typsichere Felder in die Benutzeroberfläche aufnehmen können.

interface MyType {
    typesafeProp1?: number,
    requiredProp1: string,
    [key: string]: any
}

var obj: MyType ;
obj = { requiredProp1: "foo"}; // valid
obj = {} // error. 'requiredProp1' is missing
obj.typesafeProp1 = "bar" // error. typesafeProp1 should be a number

obj.prop = "value";
obj.prop2 = 88;

Während dies die ursprüngliche Frage beantwortet , könnte die Antwort hier von @GreeneCreations eine andere Perspektive geben, wie das Problem angegangen werden kann.


13
Ich denke, das ist jetzt die beste Lösung. Ich denke, zu der Zeit, als die Frage gestellt wurde, waren Indexeigenschaften wie diese noch nicht in TypeScript implementiert.
Peter Olson

Wie wäre es mit dem nativen Objekt wie Error
Wayou

@ Wayou native Objekte wie Error und Array erben von Object. So LooseObjectkann auch einen Fehler nehmen.
Akash Kurian Jose

Können Sie überprüfen, ob das Objekt eine bestimmte (dynamische) Eigenschaft hat?
Phhbr

1
Wie schreibt man diese losen Objekte in Form eines Getter-Setzers?
JokingBatman

81

Oder alles auf einmal:

  var obj:any = {}
  obj.prop = 5;

41
Was bringt TypeScript, wenn ich so viele Dinge umwandeln anymuss, um es zu verwenden?
Wird

16
@ AjaxLeung Wenn Sie das tun müssen, verwenden Sie es falsch.
Alex

2
Siehe die zusätzliche Bearbeitung oben, in der der vorherige Objekttyp beibehalten wird.
Andre Vianna

6
@ AjaxLeung Du solltest sehr selten besetzen any. TypeScript wird verwendet, um (potenzielle) Fehler beim Kompilieren abzufangen. Wenn Sie anyFehler stummschalten, verlieren Sie die Schreibfähigkeit und können auch zu reinem JS zurückkehren. anysollte idealerweise nur verwendet werden, wenn Sie Code importieren, für den Sie keine TS-Definitionen schreiben können, oder während Sie Ihren Code von JS nach TS
migrieren

63

Ich neige dazu, anyauf die andere Seite zu stellen, dh var foo:IFoo = <any>{};so etwas ist immer noch typsicher:

interface IFoo{
    bar:string;
    baz:string;
    boo:string;     
}

// How I tend to intialize 
var foo:IFoo = <any>{};

foo.bar = "asdf";
foo.baz = "boo";
foo.boo = "boo";

// the following is an error, 
// so you haven't lost type safety
foo.bar = 123; 

Alternativ können Sie diese Eigenschaften als optional markieren:

interface IFoo{
    bar?:string;
    baz?:string;
    boo?:string;    
}

// Now your simple initialization works
var foo:IFoo = {};

Probieren Sie es online aus


5
+1 für die einzige Lösung, die die Typensicherheit gewährleistet. Stellen Sie einfach sicher, dass Sie alle nicht optionalen Eigenschaften direkt danach instanziieren, um Fehler zu vermeiden, die Sie später beißen.
Aidiakapi

Funktioniert das tatsächlich? Nach dem Kompilieren habe ich immer noch <any> {} in meinem Javascript.
bvs

4
I still have <any>{dann hast du nicht kompiliert. TypeScript würde das in seinem
emit

4
In diesen Tagen var foo: IFoo = {} as anyist bevorzugt. Die alte Syntax für Typecasting kollidierte mit TSX (Typescript-ified JSX).
Don

51

Diese Lösung ist nützlich, wenn Ihr Objekt einen bestimmten Typ hat. Wie beim Abrufen des Objekts an eine andere Quelle.

let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.

7
Dies ist die richtige Lösung für einmalige Aufgaben.
soundly_typed

Diese Antwort hat bei mir funktioniert, da ich für die Facebook-Anmeldung dem Fensterobjekt Eigenschaften hinzufügen musste . Meine erste Verwendung des Schlüsselworts as in TypeScript.
AlanObject

33

Obwohl sich der Compiler beschwert, sollte er es dennoch nach Bedarf ausgeben. Dies wird jedoch funktionieren.

var s = {};
s['prop'] = true;

2
Ja, das ist nicht wirklich eine Art Skript, du verlierst Intellisense.
Pregmatch

25

Eine weitere Möglichkeit besteht darin, auf die Eigenschaft als Sammlung zuzugreifen:

var obj = {};
obj['prop'] = "value";


2
Dies ist der prägnanteste Weg. Object.assign(obj, {prop: "value"})ab ES6 / ES2015 funktioniert auch.
Charles

9

Ich bin überrascht, dass keine der Antworten auf Object.assign verweist, da dies die Technik ist, die ich verwende, wenn ich an "Komposition" in JavaScript denke.

Und es funktioniert wie erwartet in TypeScript:

interface IExisting {
    userName: string
}

interface INewStuff {
    email: string
}

const existingObject: IExisting = {
    userName: "jsmith"
}

const objectWithAllProps: IExisting & INewStuff = Object.assign({}, existingObject, {
    email: "jsmith@someplace.com"
})

console.log(objectWithAllProps.email); // jsmith@someplace.com

Vorteile

  • Typensicherheit durchgehend, da Sie den anyTyp überhaupt nicht verwenden müssen
  • verwendet den Aggregattyp von TypeScript (wie bei der &Deklaration des Typs von angegeben objectWithAllProps), der deutlich macht, dass wir einen neuen Typ im laufenden Betrieb (dh dynamisch) erstellen.

Dinge, die Sie beachten sollten

  1. Object.assign hat seine eigenen einzigartigen Aspekte (die den meisten erfahrenen JS-Entwicklern bekannt sind), die beim Schreiben von TypeScript berücksichtigt werden sollten.
    • Es kann auf veränderliche Weise oder unveränderlich verwendet werden (ich demonstriere den unveränderlichen Weg oben, was bedeutet, dass es existingObjectunberührt bleibt und daher keine emailEigenschaft hat. Für die meisten Programmierer im funktionalen Stil ist das eine gute Sache, da das Ergebnis ist die einzige neue Änderung).
    • Object.assign funktioniert am besten, wenn Sie flachere Objekte haben. Wenn Sie zwei verschachtelte Objekte kombinieren, die nullfähige Eigenschaften enthalten, können Sie wahrheitsgemäße Werte mit undefiniert überschreiben. Wenn Sie auf die Reihenfolge der Object.assign-Argumente achten, sollte es Ihnen gut gehen.

Für mich scheint es in Fällen, in denen Sie dies zum Anzeigen von Daten verwenden müssen, gut zu funktionieren, aber wenn Sie einem Array Einträge geänderter Typen hinzufügen müssen, scheint dies nicht allzu gut zu funktionieren. Ich habe das Objekt dynamisch zusammengestellt und in einer Zeile zugewiesen und dann die dynamischen Eigenschaften in aufeinanderfolgenden Zeilen zugewiesen. Das hat mich den größten Teil des Weges dorthin gebracht, also danke.
Shafiq Jetha

8

Mit dem Spread-Operator können Sie ein neues Objekt basierend auf dem alten Objekt erstellen

interface MyObject {
    prop1: string;
}

const myObj: MyObject = {
    prop1: 'foo',
}

const newObj = {
    ...myObj,
    prop2: 'bar',
}

console.log(newObj.prop2); // 'bar'

TypeScript leitet alle Felder des ursprünglichen Objekts ab und VSCode führt die automatische Vervollständigung usw. durch.


schön, aber falls Sie prop2 in zB prop3 verwenden müssen, wird es schwer zu implementieren sein
ya_dimon

6

Simplest wird folgen

const obj = <any>{};
obj.prop1 = "value";
obj.prop2 = "another value"

5

Es ist möglich, ein Mitglied zu einem vorhandenen Objekt hinzuzufügen, indem Sie

  1. Erweiterung des Typs (lesen: Schnittstelle erweitern / spezialisieren)
  2. Wandeln Sie das ursprüngliche Objekt in den erweiterten Typ um
  3. Fügen Sie das Element zum Objekt hinzu
interface IEnhancedPromise<T> extends Promise<T> {
    sayHello(): void;
}

const p = Promise.resolve("Peter");

const enhancedPromise = p as IEnhancedPromise<string>;

enhancedPromise.sayHello = () => enhancedPromise.then(value => console.info("Hello " + value));

// eventually prints "Hello Peter"
enhancedPromise.sayHello();

1
Die beste Lösung für mich. Ich habe heute etwas Neues gelernt, danke
Maurice

Ich erhalte einen TS2352-Fehler mit diesem Code
ya_dimon

@ya_dimon probiere es auf dem TypeScript-Spielplatz aus: typescriptlang.org/play Es funktioniert gut!
Daniel Dietrich

@ DanielDietrich funktioniert jetzt .. Danke, keine Ahnung was passiert ist.
ya_dimon

Bitte schön! Schicht passiert;)
Daniel Dietrich

5

Da Sie dies nicht tun können:

obj.prop = 'value';

Wenn Ihr TS-Compiler und Ihr Linter Sie nicht einschränken, können Sie Folgendes schreiben:

obj['prop'] = 'value';

Wenn Ihr TS-Compiler oder -Linter streng ist, lautet eine andere Antwort:

var obj = {};
obj = obj as unknown as { prop: string };
obj.prop = "value";

3
Dies ist, wenn 'noImplicitAny: false' auf der tsconfig.json
LEMUEL ADANE

Andernfalls können Sie GreeneCreations beantworten.
LEMUEL ADANE

4

Speichern Sie jede neue Eigenschaft auf einem beliebigen Objekt, indem Sie sie in 'any' eingeben:

var extend = <any>myObject;
extend.NewProperty = anotherObject;

Später können Sie es abrufen, indem Sie Ihr erweitertes Objekt auf "any" zurücksetzen:

var extendedObject = <any>myObject;
var anotherObject = <AnotherObjectType>extendedObject.NewProperty;

Dies ist völlig die richtige Lösung. Nehmen wir an, Sie haben ein Objekt let o: ObjectType; .... später können Sie o in eine beliebige (<any> o) .newProperty = 'foo' umwandeln; und es kann wie (<any> o) .newProperty abgerufen werden. Keine Compilerfehler und funktioniert wie ein Zauber.
Matt Ashley

diese bremst Intellisense ... gibt es eine Möglichkeit, dies zu tun, außer Intellisense zu halten?
Pregmatch

4

Verwenden Sie Folgendes , um sicherzustellen, dass der Typ ein Object(dh Schlüssel-Wert-Paare ) ist:

const obj: {[x: string]: any} = {}
obj.prop = 'cool beans'

4
  • Fall 1:

    var car = {type: "BMW", model: "i8", color: "white"}; car['owner'] = "ibrahim"; // You can add a property:

  • Fall 2:

    var car:any = {type: "BMW", model: "i8", color: "white"}; car.owner = "ibrahim"; // You can set a property: use any type


4

Sie können dies verwenden:

this.model = Object.assign(this.model, { newProp: 0 });

3

Sie können diese Erklärung hinzufügen, um die Warnungen auszuschalten.

declare var obj: any;


3

Die beste Vorgehensweise ist die sichere Eingabe. Ich empfehle Ihnen:

interface customObject extends MyObject {
   newProp: string;
   newProp2: number;
}

3

Um Ihren vorherigen Typ beizubehalten, wandeln Sie Ihr Objekt vorübergehend in ein beliebiges Objekt um

  var obj = {}
  (<any>obj).prop = 5;

Die neue dynamische Eigenschaft ist nur verfügbar, wenn Sie die Besetzung verwenden:

  var a = obj.prop; ==> Will generate a compiler error
  var b = (<any>obj).prop; ==> Will assign 5 to b with no error;

3

Hier ist eine spezielle Version von Object.assign, die den Variablentyp bei jeder Eigenschaftsänderung automatisch anpasst. Keine zusätzlichen Variablen, Typzusicherungen, expliziten Typen oder Objektkopien erforderlich:

function assign<T, U>(target: T, source: U): asserts target is T & U {
    Object.assign(target, source)
}

const obj = {};
assign(obj, { prop1: "foo" })
//  const obj now has type { prop1: string; }
obj.prop1 // string
assign(obj, { prop2: 42 })
//  const obj now has type { prop1: string; prop2: number; }
obj.prop2 // number

//  const obj: { prop1: "foo", prop2: 42 }

Hinweis: Das Beispiel verwendet die Assertionsfunktionen von TS 3.7 . Der Rückgabetyp von assignist voidim Gegensatz zu Object.assign.


1

Wenn Sie Typescript verwenden, möchten Sie vermutlich die Typensicherheit verwenden. In diesem Fall sind nacktes Objekt und 'any' gegenindiziert.

Verwenden Sie lieber nicht Object oder {}, sondern einen benannten Typ. oder Sie verwenden möglicherweise eine API mit bestimmten Typen, die Sie um Ihre eigenen Felder erweitern müssen. Ich habe festgestellt, dass dies funktioniert:

class Given { ... }  // API specified fields; or maybe it's just Object {}

interface PropAble extends Given {
    props?: string;  // you can cast any Given to this and set .props
    // '?' indicates that the field is optional
}
let g:Given = getTheGivenObject();
(g as PropAble).props = "value for my new field";

// to avoid constantly casting: 
let k:PropAble = getTheGivenObject();
k.props = "value for props";

1

Weisen Sie einem Objekt in TypeScript dynamisch Eigenschaften zu.

Dazu müssen Sie nur folgende Typoskript-Schnittstellen verwenden:

interface IValue {
    prop1: string;
    prop2: string;
}

interface IType {
    [code: string]: IValue;
}

Sie können es so verwenden

var obj: IType = {};
obj['code1'] = { 
    prop1: 'prop 1 value', 
    prop2: 'prop 2 value' 
};

1
Ich versuche , mit Ihrem Code, aber ich erhalte keine Fehler: pastebin.com/NBvJifzN
pablorsk

1
versuchen , das initialisieren attributesFeld im Innern SomeClass und das sollte es beheben public attributes: IType = {}; pastebin.com/3xnu0TnN
Nerdroid

1

Versuche dies:

export interface QueryParams {
    page?: number,
    limit?: number,
    name?: string,
    sort?: string,
    direction?: string
}

Dann benutze es

const query = {
    name: 'abc'
}
query.page = 1

0

Die einzige Lösung, die vollständig typsicher ist , ist diese , ist jedoch etwas wortreich und zwingt Sie, mehrere Objekte zu erstellen.

Wenn Sie zuerst ein leeres Objekt erstellen müssen , wählen Sie eine dieser beiden Lösungen aus. Denken Sie daran, dass Sie bei jeder Verwendung asan Sicherheit verlieren.

Sicherere Lösung

Der Typ von objectist innen sichergetObject , was bedeutet object.a, dass er vom Typ iststring | undefined

interface Example {
  a: string;
  b: number;
}

function getObject() {
  const object: Partial<Example> = {};
  object.a = 'one';
  object.b = 1;
  return object as Example;
}

Kurze Lösung

Der Typ von objectist im Inneren nicht sichergetObject , was bedeutet object.a, dass er stringbereits vor seiner Zuweisung vom Typ ist .

interface Example {
  a: string;
  b: number;
}

function getObject() {
  const object = {} as Example;
  object.a = 'one';
  object.b = 1;
  return object;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.