Combining TypeScript and JavaScript for efficient mixins

I came across an article on MDN discussing the usage and creation of mix-ins (link). Intrigued, I decided to try implementing it in TypeScript:

type Constructor = new (...args: any) => any;

function nameMixin(Base: Constructor) {
  return class extends Base {
    #name?: string;

    name() {
      return this.#name;
    }

    setName(name: string) {
      this.#name = name;
    }
  };
}

class None {}
class Foo extends nameMixin(None) {
  constructor(private value: number) {
    super();
  }
}

const foo = new Foo(10)
foo.setName("john")
foo.name()

This implementation seems to work well, but one thing that bothers me is having to extend the arbitrary None class.

I've seen others use

Object.assign(Foo.prototype, mixin)
for mix-ins, where mixin is an object. However, I find this approach decouples the mix-in from the declaration.

Do you know of any cleaner ways to implement mix-ins?

Answer №1

"Does anyone have suggestions for cleaner ways to implement mixins?"

In my perspective, the most versatile approach among the various methods of implementing mixins in JavaScript is a function-based mixin that understands the this context, ensuring it is always applied using call on the object requiring the mixed-in functionality.

One significant advantage is that this method always operates within a delegated/bound this and can receive variables such as strings, numbers or even object references at application time. These variables can serve as privately shared (and potentially mutable) state between multiple mixins implemented similarly and the classes/factories creating objects with mixed-in behavior.

// Function-based mixin aware of `this` context.
function withSetGetName(name = '') {

  // Bound `this` context.
  Reflect.defineProperty(this, 'name', {

    // Retrieve locally scoped variable.
    get: () => name,

    // Control changing the value of the private variable.
    set: (value) => (name = value),
  });
  return this;
}

class Foo {
  #number;

  constructor(name, number) {
    this.#number = number;

    // Apply function-based mixin.
    withSetGetName.call(this, name);
  }
}

// Instance of class with mixin.
const foo = new Foo('Jim', 10);

// Plain object with mixed-in behavior.
const bar = withSetGetName.call({});

console.log(
  'foo.name =>', foo.name
);
console.log(
  "foo.name = 'John' =>", (foo.name = 'John')
);
console.log(
  'foo.name =>', foo.name
);

console.log(
  'bar.name =>', bar.name
);
console.log(
  "bar.name = 'Jane' =>", (bar.name = 'Jane')
);
console.log(
  'bar.name =>', bar.name
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Loop through each instance of a data record in a JSON document using Vue's v-for directive

I am currently working on a project that involves extracting data from a website that monitors traffic jams and maintenance work. My goal is to specifically retrieve information about traffic jams and display them individually. The code I am using utilize ...

Identifying the HTML Hidden Attribute Using JavaScript Without Dependencies

As someone working in the analytics field, I often rely on CSS selectors to address various issues. Currently, I am faced with a task on a website where I need to determine whether a <p> element is hidden or visible. There are two possible scenarios: ...

Maintaining the $index value across all pagination pages in AngularJS while matching it with the items in the data list

Is there a way to maintain the original $index numbers in my list data after pagination? For example, if data.length is 50 and they start from index 0, the first page contains 10 items ending at index 9. The next item on the second page should start at in ...

How to Avoid Duplicating Documents in MongoDB?

I'm currently exploring effective methods to avoid saving duplicate documents in MongoDB. Currently, my form captures the user's URL input. The workflow is as follows: Validate if the user's URL is valid (using dns.lookup). If the use ...

Mapping JSON data from an array with multiple properties

Here is a JSON object that I have: obj = { "api": "1.0.0", "info": { "title": "Events", "version": "v1", "description": "Set of events" }, "topics": { "cust.created.v1": { "subscribe": { ...

When loading a page with Puppeteer using the setContent method, images may not be loaded

Currently, I am experiencing an issue with Puppeteer where it does not load resources that are specified with relative paths (such as background.png in the image src or in CSS url()). When I try to load the content of a local file using setContent(), the o ...

Tips for choosing and deselecting data using jQuery

Is there a way to toggle the selection of data in my code? Currently, when I click on the data it gets selected and a tick image appears. However, I want it so that when I click again on the same data, the tick will disappear. How can I achieve this func ...

Using Javascript to change CSS in a Polymer application

Coming from a background in angular and react, I am now delving into the world of polymer. I have a polymer class called myClass with the following template. <div id="[[x]]"> Here, 'x' is a property defined in a property getter. stat ...

Challenges with window opening function while already in fullscreen view

Unsure of what might be causing the issue, but here's the problem... My code to open a new window is as follows: var opts = 'location=0,toolbar=0,menubar=0,scrollbars=0,resizable=0,height=450,width=300,right=350'; window.open('/' ...

It is impossible to alter the data contained within the input box

Objective: Upon clicking a button to display the modal, the selected data (first and last name) should be inserted into an input box and editable. The user should be able to modify the data. Issue: The data entered into the input box cannot be edited ...

NodeJS not recognizing global variable causing it to return undefined

Can a global variable be defined in a node.js function? I wish to use the variable "ko" (declared in the getNumbers function) in other functions function getNumbers(callback) { result = cio.query("SELECT numbers FROM rooms WHERE durum='1'", ...

Troubleshooting Tips: Removing a Specific Line from a Canvas Using Javascript

I need to find a method for removing a specific line without having to clear and redraw it. Learn more about clearing specific lines in Canvas with HTML5 I came across this question where everyone suggested clearing the entire page and redrawing it. Is t ...

Pass user input values to PHP via AJAX and display the outcome on a designated div

I am currently working on a project where I need to send an input value to a PHP script and display the returned value in a div using AJAX. However, I seem to be struggling with getting it to work properly. Any assistance or suggestions would be greatly ap ...

Guide to pinpointing a location with Google Maps

I am currently working on setting up a contact page that includes Google Maps to show the location of a meeting place. Here is the code I am using: JavaScript (function(){ document.getElementById('map_canvas').style.display="block"; var ...

The functionality of the Hubot script is restricted to Slack conversations where I initiate a direct message with the

At this very moment, my automated Hubot assistant is functioning properly. When I send the following message via direct message to the robot in Slack: qbot !npm bower The response provided by the robot contains a link: https://www.npmjs.com/package/bowe ...

Assistance needed in extracting the body content utilizing javascript or jquery

I am looking to swap out the body content of one page with that of another. How can I retrieve the body content from the response text of the second page in order to make this replacement? Please assist me with this. Thank you in advance, Raja ...

transform JSON data into XML format with the help of JavaScript

I need help converting a JSON object to an XML String and I'm struggling to find the right method. I recently came across a jQuery plugin called json2xml on https://gist.github.com/c4milo/3738875 but unfortunately, it does not properly escape the data ...

Choose a selection in ExtJS by finding matching attributes

Is there a convenient method to choose an item in an Ext.tree.Panel by matching it with an item based on the same attribute in an Ext.grid.Panel? For example, using something like: tree_dir.getSelectionModel().select(grid_file.getSelectionModel().getSelect ...

Error encountered during Typescript compilation: The attribute 'raw' is not found within the context of the entity 'e' in express

In many instances, I have noticed that people use express.raw() or express.raw({type: 'application/json'}) as middleware in their requests... but is .raw() a legitimate method in Express? I am currently working with TypeScript and using Express ...

Preserving the "height" declaration in jQuery post-Ajax request (adjusting height after dropdown selection loads product information, resetting heights of other page elements)

Looking for a way to set a height on product descriptions using jQuery? Check out the solution below: https://www.example.com/product-example Here is the code snippet that can help you achieve this feature: $(document).ready(function() { var $dscr = $ ...