ウェブサイト検索

TypeScriptでクラスのプロパティに値を動的に割り当てる方法


TypeScriptでMyClassに複数のプロパティを動的に割り当てたいので、クラスのプロパティを設定するために複数行のコードを書く必要がありません。私は以下のコードを書きました:

interface IMy
{
    visible?: boolean;
    text?: string;
}

class MyClass
{
    element: JQuery;

    assing(o: IMy): void
    {
        for (let [key, value] of Object.entries(o))
        {
            if (typeof value !== "undefined")
                this[key] = value;
        }
    }

    get visible(): boolean
    {
        return this.element.is(":visible");
    }

    set visible(visible: boolean)
    {
        this.element.css("display", visible ? "" : "none");
    }

    get text(): string
    {
        return this.element.html();
    }

    set text(text: string)
    {
        this.element.html(text);
    }
}

let t = new MyClass();
t.assign({ visible: true });
//instead t.visible = true;

//or

t.assign({ text: "Something" });
//instead t.text = "something";

//or

t.assign({ text: "Something", visible: false });
//instead t.visible = true; 
//        t.text = "something";

しかし、私は次の行 this[key]=value; で次のエラーが出る問題があります:

オブジェクト型のインデックス署名は暗黙的に 'any' 型を持っています。

私が変える必要があるのか、それとも私のアプローチが完全に間違っているのか?
また、インターフェースがコンストラクタのパラメータであるときに、コンストラクタでデフォルトプロパティを設定するのにも良い解決策になります。

編集済み:
私はこれらのエントリーが本当に気に入ったので、このコードを使っています:

//extensions.d.ts
interface Object
{
    entries<T>(o: any): [string, T][];
    entries(o: any): [string, any][];
}
//exntesion.js !!note js not ts
if (!Object.entries)
{
    Object.entries = function* entries(obj)
    {
        for (let key of Object.keys(obj))
        {
            yield [key, obj[key]];
        }
    };
}

編集 2:

主なアイデアは、必要なプロパティだけを設定できるコンストラクタのオーバーロードに関する問題を解決することでした。
他の誰かが役立つと感じる場合のために、完全なコードはこちらです。

interface IMy
{
    prop1?: boolean;
    prop2?: string;
    prop3?: string;
    prop4?: number;
}

class MyClass implements IMy
{
    prop1: boolean = false;
    prop2: string = "";
    prop3: string = "Something";
    prop4: number = 0;

    constructor(properties: IMy)
    {
        this.assing(properties);
    }

    assing(o: IMy): void
    {
        let that = (<any>this);
        for (let key in o)
        {
            if (o.hasOwnProperty(key))
            {
                let value = (<any>o)[key];
                if (typeof value !== "undefined" && typeof that[key] !== "undefined")
                    that[key] = value;
            }
        }
    }

}

let my1 = new MyClass({ prop1: true });
let my2 = new MyClass({ prop2: "SomeText", prop3: "Anything" });
//I set prop2 and prop3
let my3 = new MyClass({ prop4: 10 });    
//I set prop4 (fourth parameter)

console.log(my1, my2, my3);

回答 #1

このエラー自体は --noImplicitAny コンパイラオプションから発生しています。これを削除すれば、エラーはなくなります。しかし、私はこれは悪いことではないと思います。

あなたは何とかして key に型注釈を追加する必要がありますが、for .. of ループ内では問題なさそうです。

私はそのアプローチは悪くないと思いますが、プロパティの反復処理を少し違った方法で書き直す必要があります。

ちなみに、ES6 もターゲットにしていると思います(コンパイラーが .entries() について文句を言わないようにするためです。これは ES6 の機能のように見えます。配列向けで、オブジェクト向けではないようです。

編集:

別のSOの回答に触発されて - エラーをなくすために、次のように any へのキャストを追加できます:

(<any>this)[key] = value;

ただし、.entries() を使うことについての上記の内容は依然として当てはまります。

回答 #2

TypeScript 2.1 以降では、keyof とマップ型を使った方がより良いアプローチです。

function test()
{
    const my = new MyClass();
    my.assign({ prop1: 3});
}


type MyClassPartial = {
    [P in keyof MyClass]?: MyClass[P];
};

class MyClass
{
    prop1: number;
    prop2: string;
    assign(props: MyClassPartial)
    {
        for (const key of Object.keys(props))
        {
            this[key] = props[key];
        }
    }
}

関連記事