From c9504d307c686ce2deefdc6887ad2f7b044dd2e9 Mon Sep 17 00:00:00 2001 From: Davis Vaughan Date: Mon, 30 Sep 2024 13:58:35 -0400 Subject: [PATCH] Better `newActivityItemStream()` with polymorphic `this` --- .../browser/classes/activityItemStream.ts | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/vs/workbench/services/positronConsole/browser/classes/activityItemStream.ts b/src/vs/workbench/services/positronConsole/browser/classes/activityItemStream.ts index fee057218da..c23962ef3ec 100644 --- a/src/vs/workbench/services/positronConsole/browser/classes/activityItemStream.ts +++ b/src/vs/workbench/services/positronConsole/browser/classes/activityItemStream.ts @@ -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. @@ -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. * @@ -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) { @@ -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, @@ -121,7 +119,7 @@ export class ActivityItemStream { } // Create the remainder ActivityItemStream. - activityItemStream = this.newActivityItemStream!( + activityItemStream = this.newActivityItemStream( activityItemStream.id, activityItemStream.parentId, activityItemStream.when, @@ -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 /** @@ -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 } @@ -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); - } } /** @@ -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); - } }