Im wondering if there is any way to pass a reference down to an injected object in Javascript. Cannot use inheritance in this case as this class will take many objects as parameters within its constructor that are created elsewhere.
class Parent {
private Child child;
constructor(child: Child) {
this.child = child;
}
// method needs to be called from within the `child`
public log(message: string) {
// logs out "Parent logged: This is a log message from the child"
console.log(`Parent logged: ${message}`);
}
}
class Child {
private Parent: parent;
constructor() { }
log() {
parent.log("This is a log message from the child");
}
}
If the object is built in the Parent
constructor, you can just pass a reference in and then assign it to a property within Child
. However, unfortunately the object is created outside the Parent
class.
this.child = new Child(this);
CodePudding user response:
It sounds like you just want a setter method on the child that allows you to set the parent, right?
class Child {
private Parent: parent;
constructor() { }
setParent(parent) {
this.parent = parent;
}
log() {
this.parent.log("This is a log message from the child");
}
}
Editing here, since I can't put code in the comment well. This is a much more complex example, but it's a well-defined pattern.
A similar example is the Datasource
class in Apollo GraphQL, which has a base class that all of your "children" would implement, and you use that for cross-dependency with anything:
interface SomeDataSources {
someChild1: SomeChild1;
someChild2: SomeChild2;
someChild3: SomeChild3;
}
interface SomeContext {
datasources: SomeDataSources;
logger: Logger;
dbConnection: Connection;
}
class BaseDataSource {
context: SomeContext;
initialize({ context }: { context: SomeContext }) {
this.context = context;
}
}
class EachChildDoesThis extends BaseDataSource {
...
}
/**
* Instead of using a `Parent` class, this method does all of the
* dependency injection and closures necessary.
*/
const buildContext = async ({ logger, dbConnection }): Promise<SomeContext> => {
const context: SomeContext = {
logger,
dbConnection,
dataSources: {
someChild1: new SomeChild1(),
someChild2: new SomeChild2(),
someChild3: new SomeChild3(),
}
}
for (const dataSource of Object.values(context.dataSources)) {
await dataSource.initialize({
context,
});
}
return context;
};
Now you have an entire suite of functionality here that all have access both to the things you're passing in and to each other (dependency-injectedly) by doing this:
const logger = new Logger();
const dbConnection = createConnection(dbConfig);
const context = buildContext({ logger, dbConnection });
Any one of those child classes could do something like:
class SomeChild1 extends BaseDatasource {
async someMethod() {
this.context.logger.info('something something');
// or use the db
await this.context.dbConnection.doSomething();
// or even access its siblings
await this.context.dataSources.someChild2.delete('some-user-id');
}
}
Because of the dependency injection, each one of these is fully stand-alone, testable, and composable.
CodePudding user response:
You could the following:
class Parent {
name: string;
age: number;
child = {};
constructor(name: string, age: number, child: Child) {
this.child = child;
this.name = name;
this.age = age;
}
static countParents() {
return `Parent count at: 10.`;
}
log(message: string) {
console.log(`Parent logged: ${message}.`);
}
}
class Child extends Parent {
name: string;
age: number;
favoriteHero: string
message: string
constructor(name, age, favoriteHero) {
super(name, age, favoriteHero);
this.favoriteHero = favoriteHero;
}
bio() {
return `${this.name} is 12 and his favorite super hero is ${this.favoriteHero}!`
}
}
const charlie = new Child('Charlie', 12, 'Batman')
charlie.log('Good things') // Parent logged: Good things.
console.log(charlie.bio()); // Charlie is 12 and his favorite super
hero is Batman!
console.log(Parent.countParents()); // Parent count at: 10