TypeScript'teki bir nesneye özellikleri dinamik olarak nasıl atarım?


359

Programlı olarak Javascript'te bir nesneye bir özellik atamak istedim, bunu şöyle yaparım:

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

Ancak TypeScript'te bu bir hata oluşturur:

'Prop' özelliği, '{}' türünün değerinde mevcut değil

TypeScript'teki bir nesneye nasıl yeni bir özellik atamam gerekir?


1
Bilginize. Ben var bir tartışma açıldı bunu takip etmek istiyorsanız bu ilgili.
joshuapoehls

Yanıtlar:


456

objOlarak belirtmek mümkündür any, ama bu daktiloyu kullanmanın tüm amacını bozar. obj = {}ima objbir Object. Bunu işaretlemek anymantıklı değil. İstenilen kıvamı elde etmek için bir arayüz aşağıdaki gibi tanımlanabilir.

interface LooseObject {
    [key: string]: any
}

var obj: LooseObject = {};

VEYA kompakt hale getirmek için:

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

LooseObjectherhangi bir dizeye sahip alanları anahtar olarak kabul edebilir ve anydeğer olarak yazabilir.

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

Bu çözümün gerçek zarafeti, arayüze tipik güvenli alanlar ekleyebilmenizdir.

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;

Bu Orijinal soru cevaplar da, cevap burada @GreeneCreations sorunu nasıl yaklaşılması başka bir bakış açısı verebilir.


13
Bence bu şimdi en iyi çözüm. Sorunun sorulduğu zamanda bunun gibi dizin özellikleri henüz TypeScript'te uygulanmadığını düşünüyorum.
Peter Olson

Hata gibi yerel nesneye ne dersin
Wayou

@ Hata ve Dizi gibi yerel nesneler Nesneden devralınır. Yani LooseObjectbir Hata da alabilir.
Akash Kurian Jose

Nesnenin belirli (dinamik) bir özelliği olup olmadığını kontrol edebilir misiniz?
phhbr

1
bu gevşek nesneler için bunları alıcı-belirleyici şeklinde nasıl yazıyorsunuz?
Batman

80

Ya da hepsi bir arada:

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

42
Kullanmak için çok fazla şey dökmem gerekirse TypeScript'in anlamı nedir any? Sadece benim kod ekstra gürültü olur ..: /
AjaxLeung

16
@AjaxLeung Bunu yapmanız gerekiyorsa, yanlış kullanıyorsunuz.
Alex

2
Yukarıdaki nesne türünü koruyan ek düzenlemeye bakın.
Andre Vianna

6
@AjaxLeung Çok nadiren yayın yapmalısınız any. TypeScript, derleme zamanında (potansiyel) hataları yakalamak için kullanılır. Eğer artığını ise anydilsiz hatalara o zaman yazmaya gücünü kaybeder ve aynı zamanda saf JS geri gidebilir. anyideal olarak yalnızca TS tanımlarını yazamayacağınız kodu içe aktarıyorsanız veya kodunuzu
JS'den TS'ye

63

Ben anydiğer tarafa koymak eğilimindedir yani var foo:IFoo = <any>{};Yani böyle bir şey hala typesafe:

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; 

Alternatif olarak, bu özellikleri isteğe bağlı olarak işaretleyebilirsiniz:

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

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

Çevrimiçi deneyin


5
Tip güvenliğini sağlayan tek çözüm olduğu için +1. Daha sonra sizi ısırmaktan kaçınmak için, isteğe bağlı olmayan tüm özellikleri doğrudan arkasından somutlaştırdığınızdan emin olun.
Aidiakapi

Bu gerçekten işe yarıyor mu? Derledikten sonra hala javascriptimde <any> {} var.
bvs

4
I still have <any>{o zaman derlemedin. TypeScript, yayında bunu kaldıracak
basarat

4
Bugünlerde var foo: IFoo = {} as anytercih edilir. Yazım için eski sözdizimi TSX (Typescript-ified JSX) ile çarpışıyordu.
Don

51

Bu çözüm, nesneniz Belirli Tür olduğunda faydalıdır. Nesneyi başka bir kaynağa alırken olduğu gibi.

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

7
Bu bir kerelik görevler için doğru çözümdür.
soundly_typed

Bu cevap benim için çalıştı çünkü facebook girişi için pencere nesnesine özellikler eklemek zorunda kaldım . TypeScript'te as anahtar sözcüğünü ilk kez kullanıyorum .
AlanObject

33

Derleyici şikayet etmesine rağmen, yine de istediğiniz gibi çıktı. Ancak, bu işe yarayacaktır.

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

2
evet iyi, bu gerçekten tür komut dosyası yolu değil, intellisense kaybedersiniz.
18'de pregmatch

26

Bunu yapmak için bir başka seçenek de mülke bir koleksiyon olarak erişmek:

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


2
Bu en özlü yoldur. Object.assign(obj, {prop: "value"})ES6 / ES2015'ten de çalışır.
Charles

9

JavaScript'te "kompozisyon "'u düşündüğümde kullandığım teknik olduğundan, cevapların hiçbirinin Object.assign'a başvurmadığına şaşırdım.

Ve TypeScript'te beklendiği gibi çalışır:

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

Avantajları

  • tür güvenliğini yazın çünkü anytürü hiç kullanmanıza gerek yoktur
  • TypeScript'in yeni bir tür oluşturduğumuzu (yani dinamik olarak) açıkça &bildiren toplam türünü (türünü bildirirken belirtildiği gibi objectWithAllProps) kullanır.

Dikkat edilmesi gereken şeyler

  1. Object.assign, TypeScript yazarken dikkate alınması gereken kendi benzersiz yönlerine (en deneyimli JS geliştiricileri tarafından iyi bilinir) sahiptir.
    • Değişken bir şekilde veya değişmez bir şekilde kullanılabilir (yukarıdaki değişmez yolu gösteririm, yani existingObjectel değmemiş kalır ve bu nedenle bir emailözelliği yoktur. Çoğu fonksiyonel tarz programcı için, sonuç iyi çünkü tek yeni değişiklik).
    • Object.assign, daha düz nesneleriniz olduğunda en iyi sonucu verir. Null olabilecek özellikler içeren iki iç içe nesne birleştiriyorsanız, doğruluk değerlerinin üzerine tanımsız ile yazabilirsiniz. Object.assign argümanlarının sırasına dikkat ederseniz, iyi olmalısınız.

Benim için, verileri görüntülemek için bunu kullanmanız gereken durumlarda iyi çalışıyor gibi görünüyor, ancak bir diziye değiştirilmiş türlerin girişlerini eklemeniz gerektiğinde, bu çok iyi çalışmıyor gibi görünüyor. Nesneyi dinamik olarak oluşturmaya ve bir satıra atamaya, ardından ardışık satırlara dinamik özellikler atamaya başvurdum. Bu beni oraya götürdü, çok teşekkür ederim.
Shafiq Jetha

8

Forma operatörünü kullanarak eski nesneye dayalı yeni nesne oluşturabilirsiniz

interface MyObject {
    prop1: string;
}

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

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

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

TypeScript, orijinal nesnenin tüm alanlarını çıkarır ve VSCode otomatik tamamlama vb. Yapar.


güzel, ancak prop2'de prop2 kullanmanız gerekiyorsa, uygulanması zor olacaktır
ya_dimon

6

En basit takip edecek

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

5

Mevcut bir nesneye üye eklemek mümkündür.

  1. türü genişletme (okuma: arayüzü genişletme / özelleştirme)
  2. orijinal nesneyi genişletilmiş türe çevirme
  3. üyeyi nesneye ekle
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
benim için en iyi çözüm. Bugün yeni bir şey öğrendim, teşekkür ederim
Maurice

@ya_dimon bunu TypeScript Playground'da deneyin: typescriptlang.org/play İyi çalışıyor!
Daniel Dietrich

5

Bunu yapamayacağınız için:

obj.prop = 'value';

TS derleyiciniz ve linter'niz sizi sıkılaştırmazsa, şunu yazabilirsiniz:

obj['prop'] = 'value';

TS derleyiciniz veya linteriniz katı ise, başka bir cevap yazmaktır:

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

3
Bu tsconfig.json'da 'noImplicitAny: false' ise
LEMUEL ADANE

Yoksa GreeneCreations cevap yapabilirsiniz.
LEMUEL ADANE

4

Herhangi bir yeni özelliği herhangi bir nesne üzerinde 'herhangi bir' yazarak depolayın:

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

Daha sonra genişletilmiş nesnenizi 'herhangi bir' haline getirerek geri alabilirsiniz:

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

Bu tamamen doğru çözüm. Diyelim ki bir nesneniz var o: ObjectType; .... daha sonra o'yu herhangi birine (<any> o) atabilirsiniz .newProperty = 'foo'; ve (<any> o) .newProperty gibi alınabilir. Derleyici hataları yok ve bir cazibe gibi çalışır.
Matt Ashley

bu zekayı frenler ... bunun zekâyı korumanın bir yolu var mı?
18'de pregmatch

4

Türün bir Object(yani anahtar / değer çiftleri ) olduğunu garanti etmek için şunu kullanın:

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

4
  • Dava 1:

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

  • Durum 2:

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


4

bunu kullanabilirsiniz:

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

3

Uyarıları susturmak için bu bildirimi ekleyebilirsiniz.

declare var obj: any;


3

En iyi uygulama güvenli yazım kullanmaktır, size tavsiye ederim:

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

3

Önceki türünüzü korumak için nesnenizi geçici olarak herhangi bir

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

Yeni dinamik özellik yalnızca yayınlamayı kullandığınızda kullanılabilir:

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

3

İşte Object.assigndeğişkenin türünü her özellik değişikliğiyle otomatik olarak ayarlayan özel bir sürümü . Ek değişkenlere, tür iddialarına, açık türlere veya nesne kopyalarına gerek yoktur:

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 }

Not: Örnek , TS 3.7 onaylama işlevlerini kullanır . Dönüş türü assignolduğunu void, aksine Object.assign.


1

Typescript kullanıyorsanız, büyük olasılıkla güvenlik türünü kullanmak istiyorsunuz; bu durumda çıplak Nesne ve 'herhangi biri' kontrendikedir.

Object veya {} kullanmamak daha iyi, ancak bazı adlandırılmış türler; veya kendi alanlarınızla genişletmeniz gereken belirli türlerde bir API kullanıyor olabilirsiniz. Bunu çalışmak için buldum:

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

TypeScript'teki bir nesneye özellikleri dinamik olarak atayın.

Bunu yapmak için sadece böyle daktilo arayüzleri kullanmanız gerekir:

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

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

böyle kullanabilirsin

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

1
Kodunuzu deniyorum, ancak herhangi bir hata
almıyorum

1
attributesiçindeki alanı başlatmaya çalışın SomeClass ve bu sorunu düzeltmelidir public attributes: IType = {}; pastebin.com/3xnu0TnN
Nerdroid

1

Bunu dene:

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

Sonra kullan

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

0

Tam tipi kasa tek çözümdür bu , ancak birden fazla nesne oluşturmak için biraz uzun ve kuvvetler olduğunu.

Eğer varsa gereken ilk boş nesne oluşturmak, daha sonra bu iki çözümden birini seçmek. Her kullandığınızda asgüvenliği kaybettiğinizi unutmayın.

Daha güvenli çözüm

Tipi objectolan güvenligetObjectaraçları object.atipte olacakstring | undefined

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

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

Kısa çözüm

Türü objectolan güvenli değil içeride getObjectaraçları object.atip olacaktır stringhatta göreve kadar.

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

function getObject() {
  const object = {} as Example;
  object.a = 'one';
  object.b = 1;
  return object;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.