When looking at the code provided, it seems unnecessary to consider T
if you only ever examine keyof T
. The property value types of T
are consistently ignored, so there may not be a need for the Factory
type to carry them around. Instead of using Factory<T>
, I propose changing it to Factory<K extends string>
, and instead of IConfig<T>
, switch it to Record
<K, IOption>
. If your use case requires consideration of the value types of T[keyof T]
, feel free to retain the original approach as it does not impact the remainder of the solution.
Unfortunately, there is no straightforward and entirely type-safe solution available in this scenario. TypeScript does not support classes extending arbitrary generic types, even with the use of mixins. You can only extend types with known static keys, which is not the case with something like K
, where keys are only known dynamically.
One potential workaround involves utilizing type assertions within the class implementation to compensate for the inability to have arbitrary keys in this
, followed by another type assertion to create a user-accessible version of the class that behaves as desired.
Here is the proposed solution:
class _Factory<K extends string> {
config: Record<K, IOption>;
options: IOption[];
constructor(config: Record<K, IOption>) {
this.options = [];
this.config = config;
for (let key in config) {
this.options.push(config[key]);
this[key as keyof this] = config[key].value as any; // assertion
}
}
}
type Factory<K extends string> = _Factory<K> & Record<K, number>;
const Factory = _Factory as new <K extends string>(
config: Record<K, IOption>
) => Factory<K>;
By renaming Factory<K>
to
_Factory<K></code, we avoid the attempt to incorporate dynamic keys within it. Inside the constructor, various type assertions are utilized during assignment to prevent compiler complaints.</p>
<p>Following these adjustments, we introduce a type named <code>Factory<K>
along with a value named
Factory
that mimic the intended versions. The type
Factory<K>
represents an
intersection between
_Factory<K>
and
Record<K, number>
, providing objects of type
Factory<K>
with both the
config
and
options
properties from
_Factory<K>
, as well as numeric-valued properties in
K
.
Now, let's assess its functionality:
const data = {
NORMAL: {
value: 1,
label: "NORMAL",
c: 1
},
ABNORMAL: {
value: 0,
label: "ABNORMAL"
}
};
const CommonStatus = new Factory(data);
CommonStatus.ABNORMAL; // number
CommonStatus.NORMAL; // number
CommonStatus.config.ABNORMAL; // IOption
CommonStatus.config.NORMAL; // IOption
CommonStatus.options; // IOption[]
The results appear satisfactory. Wishing you the best of luck with this! Feel free to reach out if you need further assistance.
Link to code