Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending `this` in Typescript class by Object.assign

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?

like image 971
Willem van Gerven Avatar asked Jan 29 '18 06:01

Willem van Gerven


1 Answers

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.

like image 169
Estus Flask Avatar answered Sep 25 '22 20:09

Estus Flask