MOBILE-3942 core: Improve dynamic component calls

main
Noel De Martin 2022-06-22 14:40:56 +02:00
parent 0df9f3651b
commit 86355bce01
57 changed files with 179 additions and 96 deletions

View File

@ -46,7 +46,7 @@ export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent i
*
* @return Resolved when done.
*/
protected async invalidateContent(): Promise<void> {
async invalidateContent(): Promise<void> {
await CoreCourse.invalidateSections(this.instanceId);
}

View File

@ -161,7 +161,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
/**
* @inheritdoc
*/
protected async invalidateContent(): Promise<void> {
async invalidateContent(): Promise<void> {
const courseIds = this.allCourses.map((course) => course.id);
await this.invalidateCourses(courseIds);

View File

@ -79,7 +79,7 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
/**
* @inheritdoc
*/
protected async invalidateContent(): Promise<void> {
async invalidateContent(): Promise<void> {
const courseIds = this.courses.map((course) => course.id);
await this.invalidateCourses(courseIds);

View File

@ -60,7 +60,7 @@ export class AddonBlockRecentlyAccessedItemsComponent extends CoreBlockBaseCompo
*
* @return Resolved when done.
*/
protected async invalidateContent(): Promise<void> {
async invalidateContent(): Promise<void> {
await AddonBlockRecentlyAccessedItems.invalidateRecentItems();
}

View File

@ -53,7 +53,7 @@ export class AddonBlockSiteMainMenuComponent extends CoreBlockBaseComponent impl
*
* @return Resolved when done.
*/
protected async invalidateContent(): Promise<void> {
async invalidateContent(): Promise<void> {
const promises: Promise<void>[] = [];
promises.push(CoreCourse.invalidateSections(this.siteHomeId));

View File

@ -75,7 +75,7 @@ export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent im
/**
* @inheritdoc
*/
protected async invalidateContent(): Promise<void> {
async invalidateContent(): Promise<void> {
const courseIds = this.courses.map((course) => course.id);
await this.invalidateCourses(courseIds);

View File

@ -101,7 +101,7 @@ export class AddonBlockTimelineComponent extends CoreBlockBaseComponent implemen
*
* @return Resolved when done.
*/
protected invalidateContent(): Promise<void> {
invalidateContent(): Promise<void> {
const promises: Promise<void>[] = [];
promises.push(AddonBlockTimeline.invalidateActionEventsByTimesort());

View File

@ -26,7 +26,7 @@ import { AddonModAssignAssign, AddonModAssignPlugin, AddonModAssignSubmission }
@Component({
template: '',
})
export class AddonModAssignFeedbackPluginBaseComponent {
export class AddonModAssignFeedbackPluginBaseComponent implements IAddonModAssignFeedbackPluginComponent {
@Input() assign!: AddonModAssignAssign; // The assignment.
@Input() submission!: AddonModAssignSubmission; // The submission.
@ -65,12 +65,24 @@ export class AddonModAssignFeedbackPluginBaseComponent {
}
/**
* Invalidate the data.
*
* @return Promise resolved when done.
* @inheritdoc
*/
async invalidate(): Promise<void> {
return;
}
}
/**
* Interface for component to render a feedback plugin.
*/
export interface IAddonModAssignFeedbackPluginComponent {
/**
* Invalidate the data.
*
* @return Promise resolved when done.
*/
invalidate(): Promise<void>;
}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import type { IAddonModAssignFeedbackPluginComponent } from '@addons/mod/assign/classes/base-feedback-plugin-component';
import { Component, Input, OnInit, ViewChild, Type } from '@angular/core';
import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component';
import { CoreWSFile } from '@services/ws';
@ -34,7 +35,7 @@ import { AddonModAssignFeedbackDelegate } from '../../services/feedback-delegate
})
export class AddonModAssignFeedbackPluginComponent implements OnInit {
@ViewChild(CoreDynamicComponent) dynamicComponent!: CoreDynamicComponent;
@ViewChild(CoreDynamicComponent) dynamicComponent!: CoreDynamicComponent<IAddonModAssignFeedbackPluginComponent>;
@Input() assign!: AddonModAssignAssign; // The assignment.
@Input() submission!: AddonModAssignSubmission; // The submission.
@ -43,7 +44,7 @@ export class AddonModAssignFeedbackPluginComponent implements OnInit {
@Input() canEdit = false; // Whether the user can edit.
@Input() edit = false; // Whether the user is editing.
pluginComponent?: Type<unknown>; // Component to render the plugin.
pluginComponent?: Type<IAddonModAssignFeedbackPluginComponent>; // Component to render the plugin.
data?: AddonModAssignFeedbackPluginData; // Data to pass to the component.
// Data to render the plugin if it isn't supported.
@ -101,7 +102,7 @@ export class AddonModAssignFeedbackPluginComponent implements OnInit {
* @return Promise resolved when done.
*/
async invalidate(): Promise<void> {
await this.dynamicComponent.callComponentFunction('invalidate', []);
await this.dynamicComponent.callComponentMethod('invalidate');
}
}

View File

@ -24,6 +24,7 @@ import {
import { AddonModAssignHelper, AddonModAssignPluginConfig } from '../../services/assign-helper';
import { AddonModAssignSubmissionDelegate } from '../../services/submission-delegate';
import { CoreFileEntry } from '@services/file-helper';
import type { AddonModAssignSubmissionPluginBaseComponent } from '@addons/mod/assign/classes/base-submission-plugin-component';
/**
* Component that displays an assignment submission plugin.
@ -34,7 +35,7 @@ import { CoreFileEntry } from '@services/file-helper';
})
export class AddonModAssignSubmissionPluginComponent implements OnInit {
@ViewChild(CoreDynamicComponent) dynamicComponent!: CoreDynamicComponent;
@ViewChild(CoreDynamicComponent) dynamicComponent!: CoreDynamicComponent<AddonModAssignSubmissionPluginBaseComponent>;
@Input() assign!: AddonModAssignAssign; // The assignment.
@Input() submission!: AddonModAssignSubmission; // The submission.
@ -42,7 +43,7 @@ export class AddonModAssignSubmissionPluginComponent implements OnInit {
@Input() edit = false; // Whether the user is editing.
@Input() allowOffline = false; // Whether to allow offline.
pluginComponent?: Type<unknown>; // Component to render the plugin.
pluginComponent?: Type<AddonModAssignSubmissionPluginBaseComponent>; // Component to render the plugin.
data?: AddonModAssignSubmissionPluginData; // Data to pass to the component.
// Data to render the plugin if it isn't supported.
@ -99,7 +100,7 @@ export class AddonModAssignSubmissionPluginComponent implements OnInit {
* @return Promise resolved when done.
*/
async invalidate(): Promise<void> {
await this.dynamicComponent.callComponentFunction('invalidate', []);
await this.dynamicComponent.callComponentMethod('invalidate');
}
}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import type { IAddonModAssignFeedbackPluginComponent } from '@addons/mod/assign/classes/base-feedback-plugin-component';
import {
AddonModAssignPlugin,
AddonModAssignAssign,
@ -80,7 +81,7 @@ export class AddonModAssignFeedbackCommentsHandlerService implements AddonModAss
*
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> {
getComponent(): Type<IAddonModAssignFeedbackPluginComponent> {
return AddonModAssignFeedbackCommentsComponent;
}

View File

@ -23,6 +23,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons';
import { AddonModAssignFeedbackEditPdfComponent } from '../component/editpdf';
import type { IAddonModAssignFeedbackPluginComponent } from '@addons/mod/assign/classes/base-feedback-plugin-component';
/**
* Handler for edit pdf feedback plugin.
@ -39,7 +40,7 @@ export class AddonModAssignFeedbackEditPdfHandlerService implements AddonModAssi
*
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> {
getComponent(): Type<IAddonModAssignFeedbackPluginComponent> {
return AddonModAssignFeedbackEditPdfComponent;
}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import type { IAddonModAssignFeedbackPluginComponent } from '@addons/mod/assign/classes/base-feedback-plugin-component';
import {
AddonModAssignPlugin,
AddonModAssignAssign,
@ -39,7 +40,7 @@ export class AddonModAssignFeedbackFileHandlerService implements AddonModAssignF
*
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> {
getComponent(): Type<IAddonModAssignFeedbackPluginComponent> {
return AddonModAssignFeedbackFileComponent;
}

View File

@ -20,6 +20,7 @@ import { makeSingleton } from '@singletons';
import { CoreWSFile } from '@services/ws';
import { AddonModAssignSubmissionFormatted } from './assign-helper';
import { CoreFormFields } from '@singletons/form';
import type { IAddonModAssignFeedbackPluginComponent } from '@addons/mod/assign/classes/base-feedback-plugin-component';
/**
* Interface that all feedback handlers must implement.
@ -48,7 +49,9 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler {
* @param plugin The plugin object.
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent?(plugin: AddonModAssignPlugin): Type<unknown> | undefined | Promise<Type<unknown> | undefined>;
getComponent?(plugin: AddonModAssignPlugin): Type<IAddonModAssignFeedbackPluginComponent>
| undefined
| Promise<Type<IAddonModAssignFeedbackPluginComponent> | undefined>;
/**
* Return the draft saved data of the feedback plugin.
@ -209,7 +212,9 @@ export class AddonModAssignFeedbackDelegateService extends CoreDelegate<AddonMod
* @param plugin The plugin object.
* @return Promise resolved with the component to use, undefined if not found.
*/
async getComponentForPlugin(plugin: AddonModAssignPlugin): Promise<Type<unknown> | undefined> {
async getComponentForPlugin(
plugin: AddonModAssignPlugin,
): Promise<Type<IAddonModAssignFeedbackPluginComponent> | undefined> {
return await this.executeFunctionOnEnabled(plugin.type, 'getComponent', [plugin]);
}

View File

@ -20,6 +20,7 @@ import { makeSingleton } from '@singletons';
import { CoreWSFile } from '@services/ws';
import { AddonModAssignSubmissionsDBRecordFormatted } from './assign-offline';
import { CoreFormFields } from '@singletons/form';
import type { AddonModAssignSubmissionPluginBaseComponent } from '@addons/mod/assign/classes/base-submission-plugin-component';
/**
* Interface that all submission handlers must implement.
@ -122,7 +123,9 @@ export interface AddonModAssignSubmissionHandler extends CoreDelegateHandler {
getComponent?(
plugin: AddonModAssignPlugin,
edit?: boolean,
): Type<unknown> | undefined | Promise<Type<unknown> | undefined>;
): Type<AddonModAssignSubmissionPluginBaseComponent>
| undefined
| Promise<Type<AddonModAssignSubmissionPluginBaseComponent> | undefined>;
/**
* Get files used by this plugin.
@ -365,7 +368,10 @@ export class AddonModAssignSubmissionDelegateService extends CoreDelegate<AddonM
* @param edit Whether the user is editing.
* @return Promise resolved with the component to use, undefined if not found.
*/
async getComponentForPlugin(plugin: AddonModAssignPlugin, edit?: boolean): Promise<Type<unknown> | undefined> {
async getComponentForPlugin(
plugin: AddonModAssignPlugin,
edit?: boolean,
): Promise<Type<AddonModAssignSubmissionPluginBaseComponent> | undefined> {
return await this.executeFunctionOnEnabled(plugin.type, 'getComponent', [plugin, edit]);
}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import type { AddonModAssignSubmissionPluginBaseComponent } from '@addons/mod/assign/classes/base-submission-plugin-component';
import { AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin } from '@addons/mod/assign/services/assign';
import { AddonModAssignSubmissionHandler } from '@addons/mod/assign/services/submission-delegate';
import { Injectable, Type } from '@angular/core';
@ -48,7 +49,7 @@ export class AddonModAssignSubmissionCommentsHandlerService implements AddonModA
* @param edit Whether the user is editing.
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(plugin: AddonModAssignPlugin, edit = false): Type<unknown> | undefined {
getComponent(plugin: AddonModAssignPlugin, edit = false): Type<AddonModAssignSubmissionPluginBaseComponent> | undefined {
return edit ? undefined : AddonModAssignSubmissionCommentsComponent;
}

View File

@ -31,6 +31,7 @@ import { CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons';
import { AddonModAssignSubmissionFileComponent } from '../component/file';
import { FileEntry } from '@ionic-native/file/ngx';
import type { AddonModAssignSubmissionPluginBaseComponent } from '@addons/mod/assign/classes/base-submission-plugin-component';
/**
* Handler for file submission plugin.
@ -110,7 +111,7 @@ export class AddonModAssignSubmissionFileHandlerService implements AddonModAssig
*
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> {
getComponent(): Type<AddonModAssignSubmissionPluginBaseComponent> {
return AddonModAssignSubmissionFileComponent;
}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import type { AddonModAssignSubmissionPluginBaseComponent } from '@addons/mod/assign/classes/base-submission-plugin-component';
import {
AddonModAssignAssign,
AddonModAssignSubmission,
@ -106,7 +107,7 @@ export class AddonModAssignSubmissionOnlineTextHandlerService implements AddonMo
*
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> {
getComponent(): Type<AddonModAssignSubmissionPluginBaseComponent> {
return AddonModAssignSubmissionOnlineTextComponent;
}

View File

@ -23,7 +23,7 @@ import { AddonModDataData, AddonModDataEntryField, AddonModDataField, AddonModDa
@Component({
template: '',
})
export abstract class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
export abstract class AddonModDataFieldPluginBaseComponent implements OnInit, OnChanges {
@Input() mode!: AddonModDataTemplateMode; // The render mode.
@Input() field!: AddonModDataField; // The field to render.

View File

@ -16,7 +16,7 @@ import { Component, OnInit, OnChanges, ViewChild, Input, Output, SimpleChange, T
import { FormGroup } from '@angular/forms';
import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component';
import { CoreFormFields } from '@singletons/form';
import { AddonModDataEntryFieldInitialized } from '../../classes/field-plugin-component';
import { AddonModDataEntryFieldInitialized, AddonModDataFieldPluginBaseComponent } from '../../classes/base-field-plugin-component';
import { AddonModDataData, AddonModDataField, AddonModDataTemplateMode } from '../../services/data';
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
@ -29,7 +29,7 @@ import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate'
})
export class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
@ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent;
@ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent<AddonModDataFieldPluginBaseComponent>;
@Input() mode!: AddonModDataTemplateMode; // The render mode.
@Input() field!: AddonModDataField; // The field to render.
@ -42,7 +42,7 @@ export class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
// Output called when the field is initialized with a value and it didn't have one already.
@Output() onFieldInit = new EventEmitter<AddonModDataEntryFieldInitialized>();
fieldComponent?: Type<unknown>; // Component to render the plugin.
fieldComponent?: Type<AddonModDataFieldPluginBaseComponent>; // Component to render the plugin.
pluginData?: AddonDataFieldPluginComponentData; // Data to pass to the component.
fieldLoaded = false;

View File

@ -14,7 +14,7 @@
import { AddonModDataEntryField } from '@addons/mod/data/services/data';
import { Component } from '@angular/core';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
/**
* Component to render data checkbox field.
@ -23,7 +23,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
selector: 'addon-mod-data-field-checkbox',
templateUrl: 'addon-mod-data-field-checkbox.html',
})
export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginBaseComponent {
options: {
key: string;

View File

@ -22,6 +22,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreFormFields } from '@singletons/form';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldCheckboxComponent } from '../component/checkbox';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for checkbox data field plugin.
@ -35,7 +36,7 @@ export class AddonModDataFieldCheckboxHandlerService implements AddonModDataFiel
/**
* @inheritdoc
*/
getComponent(): Type<unknown> {
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldCheckboxComponent;
}

View File

@ -15,7 +15,7 @@
import { Component } from '@angular/core';
import { CoreTimeUtils } from '@services/utils/time';
import { Translate } from '@singletons';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
/**
* Component to render data date field.
@ -24,7 +24,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
selector: 'addon-mod-data-field-date',
templateUrl: 'addon-mod-data-field-date.html',
})
export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginBaseComponent {
format!: string;
displayDate?: number;

View File

@ -24,6 +24,7 @@ import { CoreFormFields } from '@singletons/form';
import { CoreTimeUtils } from '@services/utils/time';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldDateComponent } from '../component/date';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for date data field plugin.
@ -37,7 +38,7 @@ export class AddonModDataFieldDateHandlerService implements AddonModDataFieldHan
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldDateComponent;
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Component } from '@angular/core';
import { AddonModDataEntryField, AddonModDataProvider } from '@addons/mod/data/services/data';
import { AddonModDataFieldPluginComponent } from '@addons/mod/data/classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
import { CoreFileSession } from '@services/file-session';
import { CoreFileEntry } from '@services/file-helper';
@ -24,7 +24,7 @@ import { CoreFileEntry } from '@services/file-helper';
selector: 'addon-mod-data-field-file',
templateUrl: 'addon-mod-data-field-file.html',
})
export class AddonModDataFieldFileComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldFileComponent extends AddonModDataFieldPluginBaseComponent {
files: CoreFileEntry[] = [];
component?: string;

View File

@ -28,6 +28,7 @@ import { CoreFormFields } from '@singletons/form';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldFileComponent } from '../component/file';
import { CoreFileEntry } from '@services/file-helper';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for file data field plugin.
@ -41,7 +42,7 @@ export class AddonModDataFieldFileHandlerService implements AddonModDataFieldHan
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldFileComponent;
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { AddonModDataFieldPluginComponent } from '@addons/mod/data/classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
import { AddonModDataEntryField } from '@addons/mod/data/services/data';
import { Component } from '@angular/core';
import { FormBuilder } from '@angular/forms';
@ -30,7 +30,7 @@ import { DomSanitizer } from '@singletons';
selector: 'addon-mod-data-field-latlong',
templateUrl: 'addon-mod-data-field-latlong.html',
})
export class AddonModDataFieldLatlongComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldLatlongComponent extends AddonModDataFieldPluginBaseComponent {
north?: number;
east?: number;

View File

@ -23,6 +23,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreFormFields } from '@singletons/form';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldLatlongComponent } from '../component/latlong';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for latlong data field plugin.
@ -36,7 +37,7 @@ export class AddonModDataFieldLatlongHandlerService implements AddonModDataField
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldLatlongComponent;
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Component } from '@angular/core';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
/**
* Component to render data menu field.
@ -22,7 +22,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
selector: 'addon-mod-data-field-menu',
templateUrl: 'addon-mod-data-field-menu.html',
})
export class AddonModDataFieldMenuComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldMenuComponent extends AddonModDataFieldPluginBaseComponent {
options: string[] = [];

View File

@ -23,6 +23,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreFormFields } from '@singletons/form';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldMenuComponent } from '../component/menu';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for menu data field plugin.
@ -36,7 +37,7 @@ export class AddonModDataFieldMenuHandlerService implements AddonModDataFieldHan
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldMenuComponent;
}

View File

@ -14,7 +14,7 @@
import { AddonModDataEntryField } from '@addons/mod/data/services/data';
import { Component } from '@angular/core';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
/**
* Component to render data multimenu field.
@ -23,7 +23,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
selector: 'addon-mod-data-field-multimenu',
templateUrl: 'addon-mod-data-field-multimenu.html',
})
export class AddonModDataFieldMultimenuComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldMultimenuComponent extends AddonModDataFieldPluginBaseComponent {
options: {
key: string;

View File

@ -23,6 +23,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreFormFields } from '@singletons/form';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldMultimenuComponent } from '../component/multimenu';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for multimenu data field plugin.
@ -36,7 +37,7 @@ export class AddonModDataFieldMultimenuHandlerService implements AddonModDataFie
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldMultimenuComponent;
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Component } from '@angular/core';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
/**
* Component to render data number field.
@ -22,7 +22,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
selector: 'addon-mod-data-field-number',
templateUrl: 'addon-mod-data-field-number.html',
})
export class AddonModDataFieldNumberComponent extends AddonModDataFieldPluginComponent{
export class AddonModDataFieldNumberComponent extends AddonModDataFieldPluginBaseComponent{
/**
* @inheritdoc

View File

@ -18,6 +18,7 @@ import { CoreFormFields } from '@singletons/form';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldTextHandlerService } from '../../text/services/handler';
import { AddonModDataFieldNumberComponent } from '../component/number';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for number data field plugin.
@ -31,7 +32,7 @@ export class AddonModDataFieldNumberHandlerService extends AddonModDataFieldText
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldNumberComponent;
}

View File

@ -16,7 +16,7 @@ import { Component } from '@angular/core';
import { CoreFileEntry, CoreFileHelper } from '@services/file-helper';
import { CoreFileSession } from '@services/file-session';
import { CoreDomUtils } from '@services/utils/dom';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
/**
* Component to render data picture field.
@ -25,7 +25,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
selector: 'addon-mod-data-field-picture',
templateUrl: 'addon-mod-data-field-picture.html',
})
export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginBaseComponent {
files: CoreFileEntry[] = [];
component?: string;

View File

@ -28,6 +28,7 @@ import { CoreFormFields } from '@singletons/form';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldPictureComponent } from '../component/picture';
import { CoreFileEntry } from '@services/file-helper';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for picture data field plugin.
@ -41,7 +42,7 @@ export class AddonModDataFieldPictureHandlerService implements AddonModDataField
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldPictureComponent;
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component } from '@angular/core';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
/**
* Component to render data radiobutton field.
@ -21,7 +21,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
selector: 'addon-mod-data-field-radiobutton',
templateUrl: 'addon-mod-data-field-radiobutton.html',
})
export class AddonModDataFieldRadiobuttonComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldRadiobuttonComponent extends AddonModDataFieldPluginBaseComponent {
options: string[] = [];

View File

@ -23,6 +23,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreFormFields } from '@singletons/form';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldRadiobuttonComponent } from '../component/radiobutton';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for checkbox data field plugin.
@ -36,7 +37,7 @@ export class AddonModDataFieldRadiobuttonHandlerService implements AddonModDataF
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldRadiobuttonComponent;
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Component } from '@angular/core';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
/**
* Component to render data text field.
@ -22,7 +22,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
selector: 'addon-mod-data-field-text',
templateUrl: 'addon-mod-data-field-text.html',
})
export class AddonModDataFieldTextComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldTextComponent extends AddonModDataFieldPluginBaseComponent {
/**
* @inheritdoc

View File

@ -23,6 +23,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreFormFields } from '@singletons/form';
import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldTextComponent } from '../component/text';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for number data field plugin.
@ -36,7 +37,7 @@ export class AddonModDataFieldTextHandlerService implements AddonModDataFieldHan
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldTextComponent;
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { Component } from '@angular/core';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
import { AddonModDataEntryField, AddonModDataProvider } from '@addons/mod/data/services/data';
import { CoreTextUtils } from '@services/utils/text';
import { CoreWSFile } from '@services/ws';
@ -25,7 +25,7 @@ import { CoreWSFile } from '@services/ws';
selector: 'addon-mod-data-field-textarea',
templateUrl: 'addon-mod-data-field-textarea.html',
})
export class AddonModDataFieldTextareaComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldTextareaComponent extends AddonModDataFieldPluginBaseComponent {
component?: string;
componentId?: number;

View File

@ -21,6 +21,7 @@ import { makeSingleton, Translate } from '@singletons';
import { AddonModDataFieldTextHandlerService } from '../../text/services/handler';
import { AddonModDataFieldTextareaComponent } from '../component/textarea';
import { CoreFileEntry } from '@services/file-helper';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for textarea data field plugin.
@ -34,7 +35,7 @@ export class AddonModDataFieldTextareaHandlerService extends AddonModDataFieldTe
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldTextareaComponent;
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { AddonModDataEntryField } from '@addons/mod/data/services/data';
import { Component } from '@angular/core';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component';
/**
* Component to render data url field.
@ -22,7 +22,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
selector: 'addon-mod-data-field-url',
templateUrl: 'addon-mod-data-field-url.html',
})
export class AddonModDataFieldUrlComponent extends AddonModDataFieldPluginComponent {
export class AddonModDataFieldUrlComponent extends AddonModDataFieldPluginBaseComponent {
autoLink = false;
displayValue = '';

View File

@ -18,6 +18,7 @@ import { CoreFormFields } from '@singletons/form';
import { Translate, makeSingleton } from '@singletons';
import { AddonModDataFieldTextHandlerService } from '../../text/services/handler';
import { AddonModDataFieldUrlComponent } from '../component/url';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Handler for url data field plugin.
@ -31,7 +32,7 @@ export class AddonModDataFieldUrlHandlerService extends AddonModDataFieldTextHan
/**
* @inheritdoc
*/
getComponent(): Type<unknown>{
getComponent(): Type<AddonModDataFieldPluginBaseComponent> {
return AddonModDataFieldUrlComponent;
}

View File

@ -41,7 +41,7 @@ import {
} from '../../services/data';
import { AddonModDataHelper } from '../../services/data-helper';
import { CoreDom } from '@singletons/dom';
import { AddonModDataEntryFieldInitialized } from '../../classes/field-plugin-component';
import { AddonModDataEntryFieldInitialized } from '../../classes/base-field-plugin-component';
/**
* Page that displays the view edit page.

View File

@ -24,6 +24,7 @@ import { AddonModDataEntryField,
import { CoreFormFields } from '@singletons/form';
import { FileEntry } from '@ionic-native/file/ngx';
import { CoreFileEntry } from '@services/file-helper';
import type { AddonModDataFieldPluginBaseComponent } from '@addons/mod/data/classes/base-field-plugin-component';
/**
* Interface that all fields handlers must implement.
@ -42,7 +43,7 @@ export interface AddonModDataFieldHandler extends CoreDelegateHandler {
* @param field The field object.
* @return The component to use, undefined if not found.
*/
getComponent?(plugin: AddonModDataField): Type<unknown> | undefined;
getComponent?(plugin: AddonModDataField): Type<AddonModDataFieldPluginBaseComponent> | undefined;
/**
* Get field search data in the input data.
@ -140,7 +141,7 @@ export class AddonModDataFieldsDelegateService extends CoreDelegate<AddonModData
* @param field The field object.
* @return Promise resolved with the component to use, undefined if not found.
*/
getComponentForField(field: AddonModDataField): Promise<Type<unknown> | undefined> {
getComponentForField(field: AddonModDataField): Promise<Type<AddonModDataFieldPluginBaseComponent> | undefined> {
return Promise.resolve(this.executeFunctionOnEnabled(field.type, 'getComponent', [field]));
}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { InstanceMethodParams, InstanceMethodReturn } from '@/core/utils/inference';
import {
Component,
Input,
@ -64,9 +65,9 @@ import { CoreLogger } from '@singletons/logger';
templateUrl: 'core-dynamic-component.html',
styles: [':host { display: contents; }'],
})
export class CoreDynamicComponent implements OnChanges, DoCheck {
export class CoreDynamicComponent<ComponentClass> implements OnChanges, DoCheck {
@Input() component?: Type<unknown>;
@Input() component?: Type<ComponentClass>;
@Input() data?: Record<string | number, unknown>;
// Get the container where to put the dynamic component.
@ -126,16 +127,21 @@ export class CoreDynamicComponent implements OnChanges, DoCheck {
}
/**
* Call a certain function on the component.
* Call a certain method on the component.
*
* @param name Name of the function to call.
* @param params List of params to send to the function.
* @return Result of the call. Undefined if no component instance or the function doesn't exist.
* @param method Name of the method to call.
* @param params List of params to send to the method.
* @return Result of the call. Undefined if the component instance is not ready.
*/
callComponentFunction<T = unknown>(name: string, params?: unknown[]): T | undefined {
if (this.instance && typeof this.instance[name] == 'function') {
return this.instance[name].apply(this.instance, params);
callComponentMethod<Method extends keyof ComponentClass>(
method: Method,
...params: InstanceMethodParams<ComponentClass, Method>
): InstanceMethodReturn<ComponentClass, Method> | undefined {
if (typeof this.instance?.[method] !== 'function') {
return;
}
return this.instance[method].apply(this.instance, params);
}
/**

View File

@ -105,7 +105,7 @@ export abstract class CoreBlockBaseComponent implements OnInit {
*
* @return Resolved when done.
*/
protected async invalidateContent(): Promise<void> {
async invalidateContent(): Promise<void> {
return;
}

View File

@ -18,6 +18,7 @@ import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-comp
import { Subscription } from 'rxjs';
import { CoreCourseBlock } from '@/core/features/course/services/course';
import { IonRefresher } from '@ionic/angular';
import type { CoreBlockBaseComponent } from '@features/block/classes/base-block-component';
/**
* Component to render a block.
@ -29,7 +30,7 @@ import { IonRefresher } from '@ionic/angular';
})
export class CoreBlockComponent implements OnInit, OnDestroy, DoCheck {
@ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent;
@ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent<CoreBlockBaseComponent>;
@Input() block!: CoreCourseBlock; // The block to render.
@Input() contextLevel!: string; // The context where the block will be used.
@ -146,7 +147,7 @@ export class CoreBlockComponent implements OnInit, OnDestroy, DoCheck {
showErrors: boolean = false,
): Promise<void> {
if (this.dynamicComponent) {
await this.dynamicComponent.callComponentFunction('doRefresh', [refresher, done, showErrors]);
await this.dynamicComponent.callComponentMethod('doRefresh', refresher, done, showErrors);
}
}
@ -157,7 +158,7 @@ export class CoreBlockComponent implements OnInit, OnDestroy, DoCheck {
*/
async invalidate(): Promise<void> {
if (this.dynamicComponent) {
await this.dynamicComponent.callComponentFunction('invalidateContent');
await this.dynamicComponent.callComponentMethod('invalidateContent');
}
}

View File

@ -22,6 +22,7 @@ import { Params } from '@angular/router';
import { makeSingleton } from '@singletons';
import { CoreBlockDefaultHandler } from './handlers/default-block';
import { CoreNavigationOptions } from '@services/navigator';
import type { CoreBlockBaseComponent } from '@features/block/classes/base-block-component';
/**
* Interface that all blocks must implement.
@ -65,7 +66,7 @@ export interface CoreBlockHandlerData {
* The component to render the contents of the block.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*/
component: Type<unknown>;
component: Type<CoreBlockBaseComponent>;
/**
* Data to pass to the component. All the properties in this object will be passed to the component as inputs.

View File

@ -78,7 +78,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
@Input() initialSectionNumber?: number; // The section to load first (by number).
@Input() moduleId?: number; // The module ID to scroll to. Must be inside the initial selected section.
@ViewChildren(CoreDynamicComponent) dynamicComponents?: QueryList<CoreDynamicComponent>;
@ViewChildren(CoreDynamicComponent) dynamicComponents?: QueryList<CoreDynamicComponent<any>>;
// All the possible component classes.
courseFormatComponent?: Type<unknown>;
@ -567,7 +567,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
*/
async doRefresh(refresher?: IonRefresher, done?: () => void, afterCompletionChange?: boolean): Promise<void> {
const promises = this.dynamicComponents?.map(async (component) => {
await component.callComponentFunction('doRefresh', [refresher, done, afterCompletionChange]);
await component.callComponentMethod('doRefresh', refresher, done, afterCompletionChange);
}) || [];
if (this.course) {
@ -640,7 +640,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
*/
ionViewDidEnter(): void {
this.dynamicComponents?.forEach((component) => {
component.callComponentFunction('ionViewDidEnter');
component.callComponentMethod('ionViewDidEnter');
});
}
@ -649,7 +649,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
*/
ionViewDidLeave(): void {
this.dynamicComponents?.forEach((component) => {
component.callComponentFunction('ionViewDidLeave');
component.callComponentMethod('ionViewDidLeave');
});
}

View File

@ -21,6 +21,7 @@ import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
import { IonRefresher } from '@ionic/angular';
import { CoreCourseModuleCompletionData, CoreCourseSection } from '@features/course/services/course-helper';
import { CoreCourse } from '@features/course/services/course';
import type { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component';
/**
* Component to display single activity format. It will determine the right component to use and instantiate it.
@ -41,7 +42,7 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
@Input() moduleId?: number; // The module ID to scroll to. Must be inside the initial selected section.
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when any module completion changes.
@ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent;
@ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent<CoreCourseModuleMainActivityComponent>;
componentClass?: Type<unknown>; // The class of the component to render.
data: Record<string | number, unknown> = {}; // Data to pass to the component.
@ -85,7 +86,7 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
return;
}
await this.dynamicComponent?.callComponentFunction('doRefresh', [refresher, done]);
await this.dynamicComponent?.callComponentMethod('doRefresh', refresher);
if (this.course) {
const courseId = this.course.id;
@ -97,14 +98,14 @@ export class CoreCourseFormatSingleActivityComponent implements OnChanges {
* User entered the page that contains the component.
*/
ionViewDidEnter(): void {
this.dynamicComponent?.callComponentFunction('ionViewDidEnter');
this.dynamicComponent?.callComponentMethod('ionViewDidEnter');
}
/**
* User left the page that contains the component.
*/
ionViewDidLeave(): void {
this.dynamicComponent?.callComponentFunction('ionViewDidLeave');
this.dynamicComponent?.callComponentMethod('ionViewDidLeave');
}
}

View File

@ -18,6 +18,7 @@ import { AddonModAssignDefaultFeedbackHandler } from '@addons/mod/assign/service
import { AddonModAssignPlugin } from '@addons/mod/assign/services/assign';
import { CoreSitePluginsAssignFeedbackComponent } from '@features/siteplugins/components/assign-feedback/assign-feedback';
import { Translate } from '@singletons';
import type{ IAddonModAssignFeedbackPluginComponent } from '@addons/mod/assign/classes/base-feedback-plugin-component';
/**
* Handler to display an assign feedback site plugin.
@ -31,7 +32,7 @@ export class CoreSitePluginsAssignFeedbackHandler extends AddonModAssignDefaultF
/**
* @inheritdoc
*/
getComponent(): Type<unknown> | undefined {
getComponent(): Type<IAddonModAssignFeedbackPluginComponent> | undefined {
return CoreSitePluginsAssignFeedbackComponent;
}

View File

@ -18,6 +18,7 @@ import { AddonModAssignPlugin } from '@addons/mod/assign/services/assign';
import { AddonModAssignDefaultSubmissionHandler } from '@addons/mod/assign/services/handlers/default-submission';
import { Translate } from '@singletons';
import { CoreSitePluginsAssignSubmissionComponent } from '../../components/assign-submission/assign-submission';
import type { AddonModAssignSubmissionPluginBaseComponent } from '@addons/mod/assign/classes/base-submission-plugin-component';
/**
* Handler to display an assign submission site plugin.
@ -31,7 +32,7 @@ export class CoreSitePluginsAssignSubmissionHandler extends AddonModAssignDefaul
/**
* @inheritdoc
*/
getComponent(): Type<unknown> {
getComponent(): Type<AddonModAssignSubmissionPluginBaseComponent> {
return CoreSitePluginsAssignSubmissionComponent;
}

View File

@ -14,6 +14,7 @@
import { Type } from '@angular/core';
import { CoreError } from '@classes/errors/error';
import type { CoreBlockBaseComponent } from '@features/block/classes/base-block-component';
import { CoreBlockPreRenderedComponent } from '@features/block/components/pre-rendered-block/pre-rendered-block';
import { CoreBlockDelegate, CoreBlockHandler, CoreBlockHandlerData } from '@features/block/services/block-delegate';
import { CoreCourseBlock } from '@features/course/services/course';
@ -51,7 +52,7 @@ export class CoreSitePluginsBlockHandler extends CoreSitePluginsBaseHandler impl
instanceId: number,
): Promise<CoreBlockHandlerData> {
const className = this.handlerSchema.displaydata?.class || 'block_' + block.name;
let component: Type<unknown> | undefined;
let component: Type<CoreBlockBaseComponent> | undefined;
if (this.handlerSchema.displaydata?.type == 'title') {
component = CoreSitePluginsOnlyTitleBlockComponent;

View File

@ -70,7 +70,7 @@ export class CoreSitePluginsBlockComponent extends CoreBlockBaseComponent implem
*
* @return Promise resolved when done.
*/
protected async invalidateContent(): Promise<void> {
async invalidateContent(): Promise<void> {
if (!this.component || !this.method) {
return;
}

27
src/core/utils/inference.d.ts vendored 100644
View File

@ -0,0 +1,27 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* Get instance method params type.
*/
export type InstanceMethodParams<InstanceClass, Method extends keyof InstanceClass> =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
InstanceClass[Method] extends (...args: infer Args) => any ? Args : never;
/**
* Get instance method return type.
*/
export type InstanceMethodReturn<InstanceClass, Method extends keyof InstanceClass> =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
InstanceClass[Method] extends (...args: any[]) => infer R ? R : never;