1

I have an interface with a bunch of methods:

@Injectable()
export class SharedService {
    serverURL: string;
    expertMetadataSetSubject = new Subject<any>();
    metadataEmptySubject = new Subject<void>();
    singleSubject = new Subject<void>();

constructor(private http: HttpClient, private envService: EnvService) {
    this.serverURL = envService.serverURL;
}

search(): Observable<String[]> {
    return this.http.get<String[]>(this.serverURL + 'v2/meta/profile', {});
}

onMetadataEmpty() {
    this.metadataEmptySubject.next();
}

onSingleInputChange(): void {
    this.singleSubject.next();
}

etc.

This service is injected in a component, that gets the function name as an @Input(), which contains the function name, in this service, as a string. I would like to call the appropiate method dynamically.

@Component({
    selector: 'app-registration',
    templateUrl: './registration.html',
    styleUrls: ['./registration.css'],
})
export class RegistrationComponent implements OnInit {
    @Input() name: string;
    @Input() title: string;
    @Input() onChange: string;
    @Input() control!: FormControl;

    constructor(private readonly sharedService: SharedService) {}

onClick(event: any) {
    const value = event.target.innerHTML.trim();
    this.control.setValue(value);
    if (this.onChange) {
        this.sharedService[this.onChange](value);
    }
}

}

html:

<app-registration [control]="getControlByIndex('employee')" onChange="onSingleInputChange" title="namespace"></app-registration>

I got the error mentioned in the title:

error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'SharedService'.

I want to avoid adding this parameter: "suppressImplicitAnyIndexErrors": true

Any idea?

Thanks

Dvora
  • 1,175
  • 1
  • 16
  • 26

1 Answers1

1

You got this error because this.onChange could be any string, but doesn't refer to a property necessarily in SharedService object.

Using keyof should do the trick

this.sharedService[this.onChange as keyof SharedService](value);

or you could even do it like

@Input() onChange: keyof SharedService;

Now since keyof refers to attributes and method of the object best way would be either to create a type or an interface containing only method

// onChange: keyof ISharedService;
interface ISharedService {   
    onMetadataEmpty(): void;   
    onSingleInputChange(): void; 
}

// onChange: SharedServiceMethodType;
type SharedServiceMethodType = 'onMetadataEmpty' | 'onSingleInputChange';
PasNinii
  • 634
  • 8
  • 18
  • Thanks.Now I have an issue with the parameter. error TS2349: This expression is not callable. Not all constituents of type 'string | Subject | Subject | Subject | Subject | Subject | (() => Observable) | ... 7 more ... | (() => Observable<...>)' are callable. Type 'string' has no call signatures. The error is on this line: this.sharedService[this.onChange as keyof SharedService](value); – Dvora Oct 27 '22 at 14:18
  • I think it's because when you do keyof you also add the attributes. And for it consider that `this.onChange` could equal 'expertMetadataSetSubject' for instance and this attribute isn't callable You need either to create an interface containing only method signature `interface ISharedService { onMetadataEmpty(): void; onSingleInputChange(): void; }` Or restrict type instead of as keyof SharedService define a type like `export type SharedServiceMethodType = 'onMetadataEmpty' | 'onSingleInputChange'` – PasNinii Oct 27 '22 at 14:32