TypeScriptでオブジェクトにプロパティを動的に割り当てるにはどうすればよいですか?


359

プログラムでJavaScriptのオブジェクトにプロパティを割り当てたい場合は、次のようにします。

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

しかし、TypeScriptでは、これによりエラーが発生します。

プロパティ 'prop'はタイプ '{}'の値に存在しません

TypeScriptのオブジェクトに新しいプロパティを割り当てるにはどうすればよいですか?


1
ご参考までに。あなたがそれに従いたいなら私はこれに関連した議論を始めました。
joshuapoehls

回答:


456

と表記することもできますobjany、それはtypescriptを使用する目的全体を無効にします。obj = {}はを意味objObjectます。マークを付けて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;

これは元の質問に答えますが、@ GreeneCreationsによるここでの答えは、問題へのアプローチ方法に別の視点を与える可能性があります。


13
これが今のところ最良の解決策だと思います。質問の時点では、このようなインデックスプロパティはTypeScriptにまだ実装されていなかったと思います。
Peter Olson 2017年

エラーのようなネイティブオブジェクトはどうでしょう
Wayou

ErrorやArrayなどの@WayouネイティブオブジェクトはObjectから継承します。したがってLooseObject、エラーも発生する可能性があります。
Akash Kurian Jose

オブジェクトに特定の(動的)プロパティがあるかどうかを確認できますか?
phhbr 2018年

1
これらの緩いオブジェクトの場合、ゲッターセッターの形式でどのように記述しますか?
JokingBatman 2018

80

または一度にすべて:

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

42
TypeScript anyを使用するために多くのものをキャストする必要がある場合、TypeScriptのポイントは何ですか?ちょうど私のコードで余分なノイズになります..:/
AjaxLeung

16
@AjaxLeungあなたがそれをする必要があるなら、あなたはそれを間違って使っています。
Alex

2
オブジェクトの以前のタイプを保持する上記の追加編集を参照してください。
Andre Vianna

6
@AjaxLeungにキャストすることはほとんどありませんany。TypeScriptは、コンパイル時に(潜在的な)エラーをキャッチするために使用されます。anyエラーをミュートするためにキャストすると、タイピングの能力が失われ、純粋なJSに戻ることもできます。anyTS定義を記述できないコードをインポートする場合、またはコードをJSからTSに移行するときにのみ使用するのが理想的です
Precastic

63

私は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 = {};

オンラインでお試しください


5
+1は、タイプセーフを維持する唯一のソリューションです。バグが後で発生するのを避けるために、オプションでないプロパティはすべて、その直後に必ずインスタンス化してください。
アイディアカピ14

これは実際に機能しますか?コンパイル後も、JavaScriptに<any> {}が残っています。
bvs 2015年

4
I still have <any>{その後、あなたはコンパイルしていません。TypeScriptはそれをその放出で削除します
バサラト2015年

4
最近var foo: IFoo = {} as anyは好ましいです。型キャストの古い構文はTSX(Typescript-ified JSX)と衝突していました。
ドン

51

このソリューションは、オブジェクトに特定のタイプがある場合に役立ちます。他のソースにオブジェクトを取得するときのように。

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

7
これは、1回限りの割り当ての正しいソリューションです。
soundly_typed 2017年

Facebookのログインでは、ウィンドウオブジェクトにプロパティを追加する必要があったので、この回答はうまくいきました。TypeScriptでasキーワードを初めて使用しました。
AlanObject

33

コンパイラーは不平を言いますが、必要に応じて出力する必要があります。ただし、これは機能します。

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

2
はい、これは実際にはタイプスクリプトではありません。インテリセンスを失います。
pregmatch 2018年

26

そのためのもう1つのオプションは、コレクションとしてプロパティにアクセスすることです。

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


2
これが最も簡潔な方法です。Object.assign(obj, {prop: "value"})ES6 / ES2015からも動作します。
Charles

9

JavaScriptで「構成」について考えるときはいつもそれを使用する手法であるため、どの回答もObject.assignを参照していないことに驚いています。

そして、それは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

メリット

  • anyをまったく使用する必要がないため、全体にわたって型の安全性を確保する
  • TypeScriptの集約タイプ(&のタイプを宣言するときにで示されるobjectWithAllProps)を使用して、新しいタイプをオンザフライで(つまり動的に)作成していることを明確に伝える

注意すること

  1. Object.assignには、TypeScriptを作成するときに考慮する必要のある独自の独自の側面(ほとんどの経験豊富なJS開発者によく知られている)があります。
    • 変更可能な方法または不変の方法で使用できます(上記の不変の方法を示します。つまり、existingObjectそのままの状態でemailプロパティがないためです。ほとんどの関数形式のプログラマーにとって、結果は唯一の新しい変更)。
    • Object.assignは、より平坦なオブジェクトがある場合に最適に機能します。null許容プロパティを含む2つのネストされたオブジェクトを組み合わせる場合、真の値をundefinedで上書きしてしまう可能性があります。Object.assign引数の順序に注意する場合は、問題ありません。

私にとって、データを表示するためにこれを使用する必要がある場合、それは正常に動作するように見えますが、変更された型のエントリを配列に追加する必要がある場合、これはあまりうまく動作しないようです。オブジェクトを動的に作成して1行で割り当て、次に動的プロパティを連続する行で割り当てました。これでほとんどの道が開けたので、ありがとう。
Shafiq Jetha

8

スプレッド演算子を使用して、古いオブジェクトに基づいて新しいオブジェクトを作成できます

interface MyObject {
    prop1: string;
}

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

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

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

TypeScriptは元のオブジェクトのすべてのフィールドを推測し、VSCodeはオートコンプリートなどを行います。


いいですが、たとえばprop3でprop2を使用する必要がある場合、実装は困難です
ya_dimon


5

既存のオブジェクトにメンバーを追加することは可能です

  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();

1
私にとって最良の解決策。今日は何か新しいことを学びました。ありがとう
モーリス

このコードでTS2352エラーが発生する
ya_dimon

@ya_dimon TypeScript Playgroundで試してみてください:typescriptlang.org/playうまくいきます!
ダニエルディートリッヒ

@DanielDietrichが動作するようになりました。thx、何が起こったのかわかりません。
ya_dimon

どういたしまして!シフトが発生します;)
ダニエルディートリッヒ

5

あなたはこれを行うことができないので:

obj.prop = 'value';

TSコンパイラとリンターで制限されていない場合は、次のように記述できます。

obj['prop'] = 'value';

TSコンパイラまたはリンターが厳密な場合、別の答えは型キャストすることです:

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

3
これは、tsconfig.jsonで「noImplicitAny:false」の場合
LEMUEL ADANE

それ以外の場合は、GreeneCreationsの回答を行うことができます。
LEMUEL ADANE

4

'any'に型キャストすることにより、任意の種類のオブジェクトに新しいプロパティを格納します。

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

後で、拡張オブジェクトを 'any'にキャストして戻すことができます。

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

これは完全に正しい解決策です。あなたがオブジェクトを持っているとしましょうlet o:ObjectType; ....後で、oをany(<any> o).newProperty = 'foo';にキャストできます。(<any> o).newPropertyのように取得できます。コンパイラエラーはなく、魅力のように動作します。
マットアシュレイ

これはインテリセンスにブレーキをかけます...これにインテリセンスを維持する方法はありますか?
pregmatch 2018年

4

タイプがObject(つまり、キーと値のペア)であることを保証するには、以下を使用します。

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

4
  • ケース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


4

あなたはこれを使うことができます:

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

3

この宣言を追加して警告を止めることができます。

declare var obj: any;



3

以前のタイプを保持するには、オブジェクトを一時的に

  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;

3

これはの特別なバージョンでObject.assign、プロパティが変更されるたびに変数の型が自動的に調整されます。追加の変数、型の表明、明示的な型、オブジェクトのコピーは必要ありません。

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 }

注:このサンプルでは、TS 3.7 アサーション関数を使用しています。の戻り値の型はassignvoidは異なりObject.assignます。


1

Typescriptを使用している場合は、おそらくタイプセーフを使用する必要があります。その場合、裸のObjectと 'any'は反証されます。

Objectや{}ではなく、名前付きの型を使用する方がよいでしょう。または、独自のフィールドで拡張する必要がある特定のタイプのAPIを使用している可能性があります。私はこれがうまくいくことを発見しました:

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でオブジェクトにプロパティを動的に割り当てます。

そのためには、次のように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' 
};

1
私はあなたのコードにしてみてください、私は任意のエラーが表示されません:pastebin.com/NBvJifzN
pablorsk

1
初期化しようとするattributesフィールドの内部をSomeClass 、それはそれを修正する必要がありpublic attributes: IType = {}; pastebin.com/3xnu0TnN
Nerdroid

1

これを試して:

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

次にそれを使用します

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

0

完全にタイプセーフな唯一のソリューションはこれですですが、少し複雑で、複数のオブジェクトを作成する必要があります。

最初に空のオブジェクトを作成する必要がある場合は、これら2つのソリューションのいずれかを選択してください。使用するたびにas、安全性が失われるしてください。

より安全なソリューション

タイプがobjectあり、安全な内部getObject手段は、object.a型になりますstring | undefined

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

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

短い解決策

のタイプは内部で安全objectはありませんgetObject。つまり、割り当て前でもobject.aタイプになりますstring

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

function getObject() {
  const object = {} as Example;
  object.a = 'one';
  object.b = 1;
  return object;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.