web-dev-qa-db-fra.com

Comment attribuer dynamiquement des propriétés à un objet dans TypeScript?

Si je voulais affecter par programme une propriété à un objet en Javascript, je le ferais comme ceci:

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

Mais dans TypeScript, cela génère une erreur:

La propriété 'prop' n'existe pas sur la valeur de type '{}'

Comment suis-je supposé assigner une nouvelle propriété à un objet dans TypeScript?

205
Peter Olson

Il est possible de désigner obj par any, mais cela va à l’encontre de l’utilisation de TypeScript. obj = {} implique que obj est une Object. Le marquer comme any n'a aucun sens. Pour atteindre la cohérence souhaitée, une interface peut être définie comme suit.

interface LooseObject {
    [key: string]: any
}

var obj: LooseObject = {};

OU pour le rendre compact:

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

LooseObject peut accepter des champs avec n'importe quelle chaîne en tant que clé et any en tant que valeur.

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

La véritable élégance de cette solution réside dans le fait que vous pouvez inclure des champs de typesafe dans l’interface.

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;
219

Ou tout d'un coup:

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

J'ai tendance à mettre any de l'autre côté, c.-à-d. var foo:IFoo = <any>{}; Donc, quelque chose comme cela est toujours typé: 

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; 

Sinon, vous pouvez marquer ces propriétés comme facultatives: 

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

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

Essayez-le en ligne

48
basarat

Cette solution est utile lorsque votre objet a un type spécifique. Comme lors de l'obtention de l'objet vers une autre source.

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

Bien que le compilateur se plaint, il doit tout de même le sortir selon vos besoins. Cependant, cela fonctionnera.

var s = {};
s['prop'] = true;
28
Angelo R.

Une autre option consiste à accéder à la propriété en tant que collection:

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

20
Aviw

Pour garantir que le type est une Object (c'est-à-dire paires clé-valeur ), utilisez:

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

La meilleure pratique est d’utiliser une saisie sécurisée, je vous recommande:

interface customObject extends MyObject {
   newProp: string;
   newProp2: number;
}
3
Isidro Martínez

Vous pouvez ajouter cette déclaration pour faire taire les avertissements.

declare var obj: any;

3
joshuapoehls

Stockez toute nouvelle propriété sur n'importe quel type d'objet en la convertissant en "any":

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

Plus tard, vous pourrez le récupérer en convertissant votre objet étendu en "any":

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

Pour conserver votre type précédent, convertissez temporairement votre objet en

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

La nouvelle propriété dynamique ne sera disponible que lorsque vous utiliserez le cast:

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

Il est possible d’ajouter un membre à un objet existant en

  1. élargissement du type (lire: extension/spécialisation de l'interface)
  2. transtyper l'objet d'origine vers le type étendu
  3. ajouter le membre à l'objet
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();
2
Daniel Dietrich

Affecte dynamiquement des propriétés à un objet dans TypeScript.

pour ce faire, il vous suffit d'utiliser les interfaces TypeScript comme suit:

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

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

vous pouvez l'utiliser comme ça 

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

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

  • Cas 2:

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

1
ikarayel

vous pouvez utiliser ceci:

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

Le plus simple suivra

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

Si vous utilisez TypeScript, vous voulez probablement utiliser le type safety; auquel cas l'objet nu et 'tout' sont contre-indiqués.

Mieux vaut ne pas utiliser Object ou {}, mais un type nommé; ou vous utilisez peut-être une API avec des types spécifiques, que vous devez étendre avec vos propres champs. J'ai trouvé que cela fonctionne:

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
Jack Punt

Vous pouvez créer un nouvel objet basé sur l'ancien objet à l'aide de l'opérateur spread.

interface MyObject {
    prop1: string;
}

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

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

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

TypeScript déduira tous les champs de l'objet d'origine et VSCode effectuera l'auto-complétion, etc.

0
Alex

Je suis surpris qu'aucune des réponses ne fasse référence à Object.assign puisque c'est la technique que j'utilise chaque fois que je pense à la "composition" en JavaScript.

Et cela fonctionne comme prévu dans TypeScript:

interface IExisting {
    userName: string
}

interface INewStuff {
    email: string
}

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

const objectWithAllProps: IExisting & INewStuff = Object.assign({}, existingObject, {
    email: "[email protected]"
})

console.log(objectWithAllProps.email); // [email protected]

Avantages

  • tapez sécurité tout au long parce que vous n'avez pas besoin d'utiliser le type any du tout
  • utilise le type d'agrégation de TypeScript (indiqué par le & lors de la déclaration du type de objectWithAllProps), qui indique clairement que nous composons un nouveau type à la volée (c'est-à-dire de manière dynamique)

Ce qu'il faut savoir

  1. Object.assign a ses propres aspects (bien connus des développeurs JS les plus expérimentés) qui doivent être pris en compte lors de l'écriture de TypeScript.
    • Il peut être utilisé de manière modifiable ou immuable (je démontre la méthode immuable ci-dessus, ce qui signifie que existingObject reste intacte et ne possède donc pas de propriété email. Pour la plupart des programmeurs de style fonctionnel, c le résultat est le seul nouveau changement).
    • Object.assign fonctionne mieux lorsque vous avez des objets plus plats. Si vous combinez deux objets imbriqués contenant des propriétés pouvant être annulées, vous pouvez écraser les valeurs de vérité avec undefined. Si vous faites attention à l'ordre des arguments Object.assign, ça devrait aller.
0
GreeneCreations

Javascript:

myObj.myProperty = 1;

Manuscrit:

myObj['myProperty'] = 1;
0
LEMUEL ADANE