javascript - Cirkulär referens med problem vid beroendeinversion
Jag har ett problem med cirkulära referenser när jag använder detta mönster. TypeError: Class extends value undefined is not a constructor or null.
Det konstiga är att om jag flyttar field.type.ts till src/constants.ts, ger det inget fel och det fungerar som förväntat, men kraschar i enhetstesterna. Om jag lämnar field.type.ts innehåll i sin egen fil, kraschar det.
Kanske använder/förstår jag inte detta beroendeinversionsmönster på rätt sätt. Det skulle förmodligen kunna lösas genom att skicka FieldTypeToClassMapping som en parameter i Field.create(options: FieldOptions, fieldTypeMapping: FieldTypeToClassMapping), men jag vill förstå varför detta händer.
import { StringField } from './string.field.model';
import { IntegerField } from './integer.field.model';
...
export const FieldTypeToClassMapping = {
//Constructor of eg. StringField class so I can use `new FieldTypeToClassMapping[options.type](options)`;
[FieldTypeEnum.STRING]: StringField,
[FieldTypeEnum.INTEGER]: IntegerField,
};
//field/field.ts
import { FieldOptions } from 'src/interfaces/field.options.interface';
import { FieldTypeToClassMapping } from 'src/model/template/field.type.to.mapping.ts'
export abstract class Field {
value: any;
type: string;
errors: string[] = [];
public constructor(options: FieldOptions) {
this.value = options.value;
this.type = options.type;
}
public static create(options: FieldOptions): any {
try {
return new FieldTypeToClassMapping[options.type](options);
} catch (e) {
throw new Error(`Invalid field type: ${options.type}`);
}
}
}
//field/integer.field.ts
import { FieldOptions } from 'src/interfaces/field.options.interface';
import { Field } from './field.model';
export class IntegerField extends Field {
constructor(options: FieldOptions) {
super(options);
}
protected validateValueDataType() {
this.validateDataType(this.value, "value");
}
protected validateDefaultDataType() {
this.validateDataType(this.defaultValue, "defaultValue");
}
}
//field/service.ts
payload const postFields = [
{
type: "string", //FieldTypeEnum.STRING,
value: 'a name'
},
];
const postFields = [
{
type: "string",
value: "John",
},
{
type: "integer",
value: 32,
},
];
const fieldsArray = [];
postFields.forEach((item) => {
const field: Field = Field.create(item);
fieldsArray.addField(field);
});
return fieldsArray;
Svar #1
Funktionen create(options: FieldOptions) är definierad inuti klassen Field, men sedan försöker den skapa en instans av en klass som utökar Field.
Jag tror att det är där problemet uppstår. Jag känner inte till hela innehållet i dina filer, men jag föreställer mig att du högst upp i varje field.type.ts-fil importerar Field. Men eftersom Field kan instansiera vilken konkret implementation av sig själv som helst, skulle den behöva känna till dem, så du skulle behöva importera allt som utökar Field inuti Field.
Jag vet inte/förstår inte beroendeinversionsmönstret tillräckligt väl för att relatera det till din fråga. Men med den information som ges, kanske ett Factory-mönster är vad du behöver?
Du skulle kunna flytta funktionen create(options: FieldOptions) till en FieldFactory-klass. Din create-funktion är praktiskt taget redan en fabrikfunktion.