During my time as a developer I've created a lot of "typed" code. One particular issue has come up repeatedly and I finally had a moment of clarity.
The Problem
Whenever I write something like this ...
export interface ConfigType {
type: string;
}
export interface DataModel {
config: ConfigType; // ERROR HERE
[key: string]: string;
}
... I get the following error on the commented line above.
Property 'config' of type 'ConfigType' is not assignable to 'string' index type 'string'.
The issue is that the [key: string]: string;
line gets enforced on all key/value pairs on the interface.
I've seen something like the following ...
export interface Person {
id: number;
firstname: string;
lastname: string;
[key: string]: string | number;
}
... and this code does not present an error. This is because the[key: string]: string;
line gets enforced on all key/value pairs on the interface and they are string
or number
.
I came up with two approaches to solving the issue listed below. I think the first is the better approach, but I will list both for consistency.
The Type Approach
This approach seems much cleaner, creating a new data type that has the fixed and dynamic portions ANDed together.
export interface ConfigType {
type: string;
}
export type DataModel = {
config: ConfigType;
} & {
[key: string]: string;
};
The Union Approach
The following code is another resolution.
export interface ConfigType {
type: string;
}
export interface DataModel {
config: ConfigType;
[key: string]: string | ConfigType;
}
This approach has the "issue" that a new "key" could be used with another ConfigType
.
Conclusion
As I said, I think the first approach (the Type Approach) is the better of the two.
If anyone has another or better pattern, please let me know.