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?
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;
Ou tout d'un coup:
var obj:any = {}
obj.prop = 5;
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 = {};
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.
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;
Une autre option consiste à accéder à la propriété en tant que collection:
var obj = {};
obj['prop'] = "value";
Pour garantir que le type est une Object
(c'est-à-dire paires clé-valeur ), utilisez:
const obj: {[x: string]: any} = {}
obj.prop = 'cool beans'
La meilleure pratique est d’utiliser une saisie sécurisée, je vous recommande:
interface customObject extends MyObject {
newProp: string;
newProp2: number;
}
Vous pouvez ajouter cette déclaration pour faire taire les avertissements.
declare var obj: any;
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;
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;
Il est possible d’ajouter un membre à un objet existant en
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();
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'
};
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
vous pouvez utiliser ceci:
this.model = Object.assign(this.model, { newProp: 0 });
Le plus simple suivra
const obj = <any>{};
obj.prop1 = "value";
obj.prop2 = "another value"
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";
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.
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
any
du tout&
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
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).Javascript:
myObj.myProperty = 1;
Manuscrit:
myObj['myProperty'] = 1;