6

I have an object remote which is not a class instance itself. Due to the nature of Angular 2-5 I need to wrap this Object in a service so I can inject it into components. The object has an interface declared 'Remote'.

How would I make the following work?

import { Injectable } from '@angular/core';
import { remote, Remote } from 'electron';

@Injectable()
export class RemoteService implements Remote {
    constructor() {
        Object.assign(this, remote);
    }
}

I.e., how do I make a service class RemoteService which instances look like Remote, without having to manually wrap all remote's members? I cannot use extend because remote is not itself an instance of a class, just an object.

In the example above the Typescript compiler will complain that RemoteService incorrectly implements Remote (naturally). Is there any way to coerce the compiler into understand RemoteService as implementing Remote?

2
  • Did you fully implement all the methods / properties of Remote? Commented Jan 29, 2018 at 6:41
  • Well, the thing is that remote implements those, but that to use DI in angular 2+ I need remote to be wrapped in a class. So what I want is a class that exports the Remote interface, but I don't want to have to wrap every single method in a public method on the class. Hence the Object.assign(this, remote), which should copy all remote references to this. However, typescript complains that RemoteService doesn't implement Remote. Which I understand. But how to circumvent it? Commented Jan 29, 2018 at 8:38

1 Answer 1

12

TypeScript class should be augmented with an interface. This results in merged declaration that asserts that Remote methods are implemented:

import { remote, Remote } from 'electron';

export interface RemoteService extends Remote {}

@Injectable()
export class RemoteService implements Remote {
    constructor() {
        Object.assign(this, remote);
    }
}

Object.assign will only work properly if properties are constant, and methods are own and enumerable.

For more efficient inheritance, base class can be created in order to provide prototype chain:

import { remote, Remote } from 'electron';

export interface BaseRemote extends Remote {}
export class BaseRemote implements Remote {}
Object.setPrototypeOf(BaseRemote.prototype, remote);
// or
/*
export const BaseRemote = function BaseRemote() {} as Function as { new(): Remote };
BaseRemote.prototype = remote;
*/

@Injectable()
export class RemoteService extends BaseRemote {
    /* custom methods */
}

If a class extends an exotic object that has restrictions on this context (see the example with native sessionStorage object), or object methods were bound, wrapper methods should be provided for original methods any way. If wrapper methods are created programmatically (by iterating over properties with for..in, etc) and not through class syntax, merged declaration should be additionally used for proper typing.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, this "TypeScript class should be augmented with an interface. This results in merged declaration that asserts that Remote methods are implemented" is exactly what I wanted!
I had a library with a factory and a lot of dependencies and I could nicely extend the instance without touching vendor code. Such a nice thing in a good answer!
...but I get that error: Cannot assign to read only property 'prototype' of function 'class BaseRemote { (with strict mode)
@DanielW. Reassignment of class proto indeed may not work depending on a setup. See the update, I expect it to be more universal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.