In my code, I have a function that takes in an object called DataObject
and uses certain properties from it to create instances of a class.
To determine which data object items should be assigned to which class properties, I use mappings in the form of a list of tuples. Each tuple consists of a key from the data object and a corresponding property name in the class.
interface DataObject<T> {
[name: string]: T[keyof T];
}
// list of mappings
type MappingsList<T> = [string, keyof T][];
// function for creating class instances and assigning properties based on mappings
function AttrConstructor<T>(
ItemClass: { new (): T },
mappings: MappingsList<T>,
dataObj: DataObject<T>
) {
const instance = new ItemClass();
mappings.forEach(([fromLabel, toLabel]) => {
instance[toLabel] = dataObj[fromLabel];
});
return instance;
}
Everything works fine when dealing with one class at a time. However, issues arise when the data object contains properties and values for multiple classes.
class Class1 {
Prop1a: string;
Prop1b: number;
}
class Class2 {
Prop2a: string;
Prop2b: number;
}
declare const row: DataObject<Class1 & Class2>;
const mappings1: MappingsList<Class1> = [["prop1a", "Prop1a"]];
const makeNew1 = (row: DataObject<Class1>) =>
AttrConstructor(Class1, mappings1, row);
const instance1 = makeNew1(row);
This results in an error:
Argument of type 'DataObject<Class1 & Class2>' is not assignable to parameter of type 'DataObject<Class1>'.
Type 'Class1' is not assignable to type 'Class1 & Class2'.
Type 'Class1' is not assignable to type 'Class2'.
Property 'Prop2a' is missing in type 'Class1'.
The question is how can I indicate that having extra properties in the data object is acceptable because the AttrConstructor
function will only assign relevant properties to each class?
Note: Interestingly, no errors were displayed during coding this example until the file was saved, so perhaps my tsconfig.json file could be relevant:
// tsconfig.json
{
"include": ["src/**/*"],
"compilerOptions": {
"strict": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"module": "commonjs",
"outDir": "dist",
"pretty": true,
"lib": ["es2015"],
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}