Skip to content

Commit

Permalink
Better newActivityItemStream() with polymorphic this
Browse files Browse the repository at this point in the history
  • Loading branch information
DavisVaughan committed Sep 30, 2024
1 parent a7bfa6b commit c9504d3
Showing 1 changed file with 35 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class ActivityItemStream {
/**
* Gets the ActivityItemStream array.
*/
private activityItemStreams: ActivityItemStream[] = [];
private activityItemStreams: this[] = [];

/**
* Gets the ANSIOutput that is processing this ActivityItemStream.
Expand Down Expand Up @@ -48,7 +48,7 @@ export class ActivityItemStream {
/**
* Constructor.
*
* Never to be called directly, as the result won't be fully specialized.
* Never to be called directly.
* Internally, use `newActivityItemStream()` instead.
* Externally, use `ActivityItemOutputStream` or `ActivityItemErrorStream` constructors instead.
*
Expand All @@ -75,9 +75,7 @@ export class ActivityItemStream {
* @param activityItemStream The ActivityItemStream to add.
* @returns The remainder ActivityItemStream, or undefined.
*/
public addActivityItemStream(
activityItemStream: ActivityItemStream
): ActivityItemStream | undefined {
public addActivityItemStream(activityItemStream: this): this | undefined {
// If this ActivityItemStream is terminated, copy its styles to the ActivityItemStream being
// added and return it as the remainder ActivityItemStream to be processed.
if (this.terminated) {
Expand All @@ -100,7 +98,7 @@ export class ActivityItemStream {
const remainderText = activityItemStream.text.substring(newlineIndex + 1);

// Add an ActivityItemStream with the text containing the newline.
this.activityItemStreams.push(this.newActivityItemStream!(
this.activityItemStreams.push(this.newActivityItemStream(
activityItemStream.id,
activityItemStream.parentId,
activityItemStream.when,
Expand All @@ -121,7 +119,7 @@ export class ActivityItemStream {
}

// Create the remainder ActivityItemStream.
activityItemStream = this.newActivityItemStream!(
activityItemStream = this.newActivityItemStream(
activityItemStream.id,
activityItemStream.parentId,
activityItemStream.when,
Expand All @@ -143,25 +141,6 @@ export class ActivityItemStream {

//#endregion Public Methods

//#region Protected Methods

/**
* Constructor for typed ActivityItemStream instances
*
* Must be overriden by specializations.
*
* Used to ensure that newly created ActivityItemStreams returned by `addActivityItemStream()`
* retain their original type, i.e. either ActivityItemOutputStream or ActivityItemErrorStream.
*
* @param id The identifier.
* @param parentId The parent identifier.
* @param when The date.
* @param text The text.
*/
protected newActivityItemStream?(id: string, parentId: string, when: Date, text: string): ActivityItemStream;

//#endregion Protected Methods

//#region Private Methods

/**
Expand All @@ -177,6 +156,36 @@ export class ActivityItemStream {
}
}

/**
* Polymorphic constructor for internal creation of new `ActivityItemStream`s
*
* Uses polymorphic `this` to actually return extension class types, like
* `ActivityItemOutputStream` and `ActivityItemErrorStream`.
*
* Note that we have to manually cast `this.constructor()` to the right type, as otherwise
* it is just a generic `Function`.
* https://github.com/microsoft/TypeScript/issues/3841
* https://stackoverflow.com/questions/64638771/how-can-i-create-a-new-instance-of-a-class-using-this-from-within-method
*
* @param id The identifier.
* @param parentId The parent identifier.
* @param when The date.
* @param text The text.
* @returns A newly constructed activity item stream of type `this`.
*/
private newActivityItemStream(
id: string,
parentId: string,
when: Date,
text: string
): this {
const constructor = (
this.constructor as
new (id: string, parentId: string, when: Date, text: string) => this
);
return new constructor(id, parentId, when, text);
}

//#endregion Private Methods
}

Expand All @@ -187,10 +196,6 @@ export class ActivityItemOutputStream extends ActivityItemStream {
constructor(id: string, parentId: string, when: Date, text: string) {
super(id, parentId, when, text);
}

protected override newActivityItemStream(id: string, parentId: string, when: Date, text: string): ActivityItemStream {
return new ActivityItemOutputStream(id, parentId, when, text);
}
}

/**
Expand All @@ -200,8 +205,4 @@ export class ActivityItemErrorStream extends ActivityItemStream {
constructor(id: string, parentId: string, when: Date, text: string) {
super(id, parentId, when, text);
}

protected override newActivityItemStream(id: string, parentId: string, when: Date, text: string): ActivityItemStream {
return new ActivityItemErrorStream(id, parentId, when, text);
}
}

0 comments on commit c9504d3

Please sign in to comment.