簡體   English   中英

TypeScript:動態設置類型化 object 屬性

[英]TypeScript: Dynamically set typed object properties

我是 TypeScript 的新手,我正在嘗試將一些自定義組件/插件移植到 TS。

我似乎無法正確設置的一件事是動態設置(鍵入)object 屬性(即,當屬性名稱是變量時)。

對此的最佳實踐解決方案/模式真的會幫助我。

我的代碼:

interface Options {
    repeat: boolean;
    speed: number;
}

class MyPlugIn {
    $el:HTMLElement;
    options:Options;

    constructor ($el:HTMLElement, options:Partial<Options> = {}) {
        this.$el = $el;

        // Set default options, override with provided ones
        this.options = {
            repeat: true,
            speed: 0.5,
            ...options
        };

        // Set options from eponymous data-* attributes
        for (const option in this.options) {
            if (this.$el.dataset[option] !== undefined) {
                let value: any = this.$el.dataset[option];

                // Cast numeric strings to numbers
                value = isNaN(value) ? value : +value;

                // Cast 'true' and 'false' strings to booleans
                value = (value === 'true') ? true : ((value === 'false') ? false : value)

                // Attempt 1:
                // ERROR: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Options'.
                this.options[option] = value;
                ~~~~~~~~~~~~~~~~~~~~

                // Attempt 2 (with assertions):
                // ERROR (left-hand): Type 'string' is not assignable to type 'never'
                // ERROR (right-hand): Type 'option' cannot be used as an index type.
                this.options[option as keyof Options] = value as typeof this.options[option];
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                ~~~~~~
                          
            } 
        }

        /* ... */
    }

    /* ... */
}

謝謝!

在你的情況下,他們不是很多選擇。 由於 Options 具有不同類型的鍵,因此您可以執行以下操作

const data = this.$el.dataset[option];

if (data !== undefined) {
    if(option === 'repeat') {
        const value: boolean = Boolean(data);

        this.options.repeat = value;
        ...
    }
    ...
}

或者使用開關盒。

問題在於從字符串轉換為您的類型(數字/ boolean /...)

我不能說這是否是最佳實踐,但這種方法對我來說似乎是明智的。 我會通過另一個屬性genericOptions修改Options接口:

interface Options {
    repeat: boolean;
    speed: number;
    genericOptions: { [key: string]: string };
}

此屬性是可以通過字符串索引以返回字符串的任何舊類型。

你的構造函數現在看起來像這樣:

constructor ($el:HTMLElement, options:Partial<Options> = {}) {
        this.$el = $el;

        // Set default options, override with provided ones
        this.options = {
            repeat: true,
            speed: 0.5,
            // Just an empty object by default, or you could make the `genericOptions`
            // optional, depending on preference.
            genericOptions: {},
            ...options
        };

        // Set options from eponymous data-* attributes
        for (const option in this.options) {
            if (this.$el.dataset[option] !== undefined) {
                let value: any = this.$el.dataset[option];

                // Cast numeric strings to numbers
                value = isNaN(value) ? value : +value;

                // Cast 'true' and 'false' strings to booleans
                value = (value === 'true') ? true : ((value === 'false') ? false : value)

                // Set whatever generic options you need to.
                this.options.genericOptions[option] = value;
            }
        }
         /* ... */
    }

簡而言之,只需讓 TSC 知道您的Option類型將具有動態屬性。

interface Options {
    [key: string]: unknown;
    repeat: boolean;
    speed: number;
}

然后您可以繼續動態分配值

this.options[option] = value;

您的問題與此處描述的問題非常相似

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM