Как мне динамически назначать свойства объекту в TypeScript?

191

Если бы я хотел программно назначить свойство для объекта в Javascript, я бы сделал это следующим образом:

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

Но в TypeScript это порождает ошибку:

Свойство 'prop' не существует при значении типа '{}'

Как мне назначить какое-либо новое свойство объекту в TypeScript?

  • 0
    FYI. Я открыл дискуссию, связанную с этим, если вы хотите следовать ей.
Теги:

17 ответов

218
Лучший ответ

Обозначение obj можно обозначить как any, но это побеждает всю цель использования typescript. obj = {} означает, что obj является Object. Пометка как any не имеет смысла. Для достижения желаемой консистенции интерфейс можно определить следующим образом.

interface LooseObject {
    [key: string]: any
}

var obj: LooseObject = {};

ИЛИ сделать его компактным:

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

LooseObject может принимать поля с любой строкой в ​​качестве ключа, а any - как значение.

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

Реальная элегантность этого решения заключается в том, что вы можете включать в интерфейс типы полей.

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;
  • 10
    Я думаю, что это лучшее решение сейчас. Я думаю, что в то время, когда задавался вопрос, свойства индекса, подобные этому, еще не были реализованы в TypeScript.
  • 0
    как насчет нативного объекта, такого как ошибка
Показать ещё 4 комментария
67

Или все за один раз:

  var obj:any = {}
  obj.prop = 5;
  • 51
    Это решение удаляет информацию о типе
  • 26
    Какой смысл в TypeScript, если мне приходится приводить так много вещей к any , чтобы использовать его? Просто становится лишним шумом в моем коде ..: /
Показать ещё 3 комментария
46

Я склонен ставить any с другой стороны, т.е. var foo:IFoo = <any>{}; Итак, что-то вроде этого все еще существует:

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; 

В качестве альтернативы вы можете пометить эти свойства как необязательные:

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

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

Попробуйте в Интернете

  • 3
    +1 за единственное решение, обеспечивающее безопасность типов. Просто убедитесь, что вы создаете все необязательные свойства сразу после него, чтобы избежать ошибок, кусающих вас позже.
  • 0
    Это на самом деле работает? После компиляции у меня все еще есть <any> {} в моем JavaScript.
Показать ещё 2 комментария
33

Это решение полезно, когда ваш объект имеет определенный тип. Например, при получении объекта другому источнику.

let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.
  • 4
    Это правильное решение для одноразовых заданий.
  • 0
    Этот ответ работал для меня, потому что для входа в Facebook мне пришлось добавить свойства объекта окна . Мое первое использование ключевого слова as в TypeScript.
28

Хотя компилятор жалуется, он все равно должен выводить его по мере необходимости. Однако это будет работать.

var s = {};
s['prop'] = true;
  • 0
    да, ну, это не совсем сценарий типа, вы теряете intellisense.
21

Еще один вариант: доступ к свойству в виде коллекции:

var obj = {};
obj['prop'] = "value";
  • 0
    Это самый лаконичный способ. Object.assign(obj, {prop: "value"}) из ES6 / ES2015 тоже работает.
4

Чтобы гарантировать, что тип представляет собой Object (то есть пары ключ-значение), используйте:

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

Лучшей практикой является использование безопасной печати, я рекомендую вам:

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

Сохраните любое новое свойство на любом объекте, указав его на "any":

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

Позже вы можете получить его, отбросив расширенный объект до "any":

var extendedObject = <any>myObject;
var anotherObject = <AnotherObjectType>extendedObject.NewProperty;
  • 0
    Это абсолютно правильное решение. Допустим, у вас есть объект let o: ObjectType; .... позже вы можете привести o к любому (<any> o) .newProperty = 'foo'; и его можно получить как (<any> o) .newProperty. Нет ошибок компилятора и работает как шарм.
  • 0
    это тормозит intellisense ... есть ли способ это сделать, кроме как сохранить intellisense?
3

Вы можете добавить это объявление, чтобы отключить предупреждения.

declare var obj: any;

  • 0
    У меня не работает (v0.8.3.1) в VS 2012.
2

Можно добавить члена к существующему объекту

  1. расширение типа (читай: расширять/специализировать интерфейс)
  2. приведите исходный объект к расширенному типу
  3. добавить член к объекту
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();
  • 0
    лучшее решение для меня. Сегодня я узнал что-то новое, спасибо
2

Чтобы сохранить предыдущий тип, временно создайте свой объект для любого

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

Новое динамическое свойство будет доступно только при использовании трансляции:

  var a = obj.prop; ==> Will generate a compiler error
  var b = (<any>obj).prop; ==> Will assign 5 to b with no error;
1
  • Случай 1:

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

  • Случай 2:

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

1

Если вы используете Typescript, вероятно, вы хотите использовать тип безопасности; в этом случае голый объект и "любой" противопоказаны.

Лучше не использовать Object или {}, а какой-нибудь именованный тип; или вы можете использовать API с определенными типами, которые вам нужно расширить своими собственными полями. Я нашел это, чтобы работать:

class Given { ... }  // API specified fields; or maybe it 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

динамически назначать свойства объекту в TypeScript.

Для этого вам просто нужно использовать машинописные интерфейсы, например:

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

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

Вы можете использовать это так

var obj: IType = {};
obj['code1'] = { 
    prop1: 'prop 1 value', 
    prop2: 'prop 2 value' 
};
  • 0
    Я пытаюсь с вашим кодом, но я не получаю никакой ошибки: pastebin.com/NBvJifzN
  • 0
    попробуйте инициализировать поле attributes внутри SomeClass и это должно исправить его public attributes: IType = {}; pastebin.com/3xnu0TnN
0

Я удивлен, что ни один из ответов не ссылается на Object.assign с тех пор, как я использую технику, когда я думаю о "композиции" в JavaScript.

И это работает как положено в 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]

преимущества

  • Тип безопасности во всем, потому что вам не нужно использовать any тип вообще
  • использует агрегатный тип TypeScript (как обозначено символом & при объявлении типа objectWithAllProps), что четко objectWithAllProps, что мы создаем новый тип

Что нужно знать

  1. Object.assign имеет свои уникальные аспекты (которые хорошо известны большинству опытных разработчиков JS), которые следует учитывать при написании TypeScript.
    • Он может быть изменчивым или неизменным (я демонстрирую неизменный способ выше, что означает, что existingObject объект остается неизменным и, следовательно, не имеет свойства email. Для большинства программистов в функциональном стиле это хорошо, так как результат - единственное новое изменение).
    • Object.assign работает лучше всего, когда у вас есть более плоские объекты. Если вы объединяете два вложенных объекта, которые содержат обнуляемые свойства, вы можете в итоге перезаписать истинные значения неопределенными. Если вы следите за порядком аргументов Object.assign, все будет в порядке.
-1

Если вы можете использовать функции ES6 JavaScript, вы можете использовать Имена вычисляемых свойств, чтобы справиться с этим очень легко:

var req = {id : 0123456};    
var response = {responses: {[req.id]: 'The 0123456 response message'}};

Ключ объекта [req.id] имеет динамическое значение

  • 3
    этот вопрос о машинописи не es6 js

Ещё вопросы

Сообщество Overcoder
Наверх
Меню