What is it about Kyle Simpson's OLOO methodology that seems to swim against the tide of Typescript's popularity?

Disclaimer: this post might come across as impulsive. Warning for Typescript beginners! Also, a bit of a vent session.

Recently, I delved into the OLOO approach from the YDKJS book series within a Typescript and Node environment.

// ideal JS syntax

let Account = {
  get id(){
    return this._id;
  },
  get name(){
    return this._name;
  },
  init(id, name){
    this._id = id;
    this._name = name;
  }
}

let TypedAccount = {
  identify(){
    console.log(`This is ${this.name}'s ${this._type} account`);
  },
  init_L2(type){  
    this._type = type;
  }
}
Object.setPrototypeOf(TypedAccount, Account);

function createAccount(id, name, type){
  let instance = Object.create(TypedAccount);
  instance.init(id, name);
  instance.init_L2(type);
  return instance;
}

let o1 = createAccount(101, 'Tom', 'Savings'),
o2 = createAccount(102, 'Jerry', 'Current');
console.log (o1.identify());
console.log (o2.identify());

The primary appeal of OLOO was its simplicity. However, due to the Typescript compiler, I find myself writing more code than necessary; something I wouldn't have to do with the class-based approach.

  1. I have to define an interface like IAccount for each type like Account, in order to ensure client usages can be checked for/auto-completed. Although, I sometimes resort to using the any escape when needed.
  2. TS complains about using undeclared fields, so I need to specify all the fields and their types before accessing them with this.field. It's not too much effort but still adds complexity. For example, _id : defaultValue;
  3. When dealing with object literals that include a map [strings => numbers], I use a nested object. But TS requires me to provide the type for both key and value. This leads to creating an interface to annotate the field.

interface IMapStringsToNumbers {
   [ key: string ]: number;
}

// 
let Account = {
   _holdings : <IMapStringsToNumbers> {}

Perhaps the last two points are not directly related to OLOO. Is there a simpler solution?

Answer №1

Creating a class Account in TypeScript results in the simultaneous creation of two entities:

  • An entity named Account which represents the type of instances of the Account class during compilation
  • A run-time entity (variable) named Account which represents the class itself (similar to a constructor in Javascript)

All the necessary connections are established, making it clear that new Account returns an object of the Account type.

However, if you use let Account = ..., you only create a variable without any automatic type tracking by TypeScript. It won't recognize relationships between Account and TypedAccount based on prototype assignments.

Subjectively speaking, implementing this "simple" pattern may require adding lines like:

init_L2(type){  // avoid collision with base#init

or

Object.setPrototypeOf(TypedAccount, Account)

In conclusion: Avoid these complexities. Stick with classes.

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

Unable to synchronize Rijdnael encryption across C# and Javascript/Node platforms

I have encountered an issue while trying to convert a Rijndael encryption function from C# to Node. Despite using the same Key, IV, Mode, and Block Size, I am unable to achieve matching results. What could be causing this discrepancy? C# MRE: using System ...

I am looking to show images based on the number chosen from the dropdown menu in CodeIgniter

When a number is selected from the dropdown menu, I want to display images accordingly. The options in the dropdown are 9, 12, and 18. Here is the code snippet for my view page: <form action="<?php echo base_url();?>roxcontrol/numberdisplay" id=" ...

In Pure JavaScript, an HTML element is added every time the click event is triggered

Hey everyone, I'm facing a small issue and I could use some help fixing it. I need to implement an onclick event that adds HTML code every time it's clicked. I am hesitant to use innerHTML due to its potential risks. Here is the code snippet: bu ...

Is there a way for me to properly type the OAuthClient coming from googleapis?

Currently, I am developing a nodemailer app using Gmail OAuth2 in TypeScript. With the configuration options set to "noImplicitAny": true and "noImplicitReturns": true, I have to explicitly define return types. Here is a snippet of my code: import { goog ...

Using three.js to control the opacity and size of points

I have returned with question number two about points. My query this time revolves around changing the opacity from 0 to 1 and back within specific pixel distances from the emitter. var particleCount = 14, particles = new THREE.Geometry(), pMaterial = new ...

Unable to see Next.js page in the browser window

I have set up a next.js project with App Router and my file structure under the app folder looks like this: *some other files* . . user | [id] | | page.tsx | @users | | page.tsx | layout.tsx | page.tsx I am ...

Leveraging split and map functions within JSX code

const array = ['name', 'contact number'] const Application = () => ( <div style={styles}> Unable to display Add name & contact, encountering issues with splitting the array). </div> ); I'm facing difficul ...

Is there a way I can link a variable to a URL for an image?

Creating v-chip objects with dynamic variable names and images is causing an issue. The image source string depends on the name provided, but when I bind the name to the source string, the image fails to load. Despite trying solutions from a similar questi ...

The error message "Required parameter not provided" appeared when trying to utilize a nested dynamic route in Next.js

Issue: The error message indicates that the required parameter (plantName) was not provided as a string in getStaticPaths for /plants/[plantName]/streaming-data/[panel] The error above is being displayed. My folder structure follows this pattern: plants & ...

Seeking to duplicate script for a new table without making any changes to the original script

I am working with two tables that require the capability to dynamically add and delete rows using separate scripts. How can I modify the second script so that it only affects the second table and not the first one? Table: <table id="myTable" class=" t ...

Struggling to properly implement background images in a React application using Tailwind CSS

I'm currently developing a React application using Tailwind CSS for styling. In my project, I have an array of items called "trending," and I'm attempting to iterate through them to generate a series of divs with background images. However, I am ...

React-Image-Annotate encountered an issue: SyntaxError - The import statement cannot be used outside a module

Encountering an issue while trying to set up react-image-annotate. Here is the problem I am facing initially: https://i.stack.imgur.com/XgYPd.png This is how I have implemented it: import React from 'react' import ReactImageAnnotate from ' ...

Creating a versatile Ajax function that can be used with various parameters

As I develop software that utilizes ajax calls to a web API for retrieving data, I realized the need to refactor my code. One key observation was that many of these ajax calls shared similarities in functionality, differing only in the parameters passed to ...

Vuetify 3 now displays full text in v-autocomplete without an ellipsis

Trying to truncate long text in a v-autocomplete component using Vuetify 3 and text-overflow: ellipsis, but it's not working. Check out the code below: <div id="app"> <v-app id="inspire"> <v-row align="cen ...

Tips for adjusting the position of an infowindow in ArcGIS

I have implemented the use of infowindow in arcgis to display certain information. https://i.sstatic.net/Dnpas.jpg Currently, the infowindow is appearing directly over my icon. Is there a way to adjust its position if it covers the icon? ...

AngularJS - Ensuring the <script> tag is included only after all directives have been rendered

Forgive me if this question has been asked before. I've spent quite some time looking for a solution to no avail. I'm in the process of converting an existing application, which relies heavily on jQuery, to utilize AngularJS. However, I've ...

Using TypeScript with React's forwardRef

Here's my code where I have utilized React's forwardRef: interface PropsDummy {} const ProfileMenu = forwardRef<HTMLInputElement, PropsDummy>((props, ref) => { console.log(ref.current); } However, I'm encountering a TypeScript e ...

Unusual behavior experienced with raycasting in Three JS when objects are are repositioned

Software Versions THREE.ObjectLoader2: 2.4.1 THREE.LoaderSupport.MeshBuilder: 1.2.1 THREE.LoaderSupport.WorkerSupport: 2.2.0 THREE.WebGLRenderer: 93 THREE.REVISION: 93 Anomalies Discovered During a raycast operation on objects within my scene, I encount ...

Angular 7's innovative method for handling singleton instances: Dynamic provider

In my Angular application, I have the ability to display lists of videos or articles along with their details. There are two main components: ContentListPage and ContentDetailsPage, which serve the same purpose for both videos and articles. The only diff ...

Struggling to make dynamically created SVG 'use' elements function properly

SVG offers a unique system with symbol and use where icons can be defined once and reused throughout the SVG using use. However, I am having trouble getting it to work from JavaScript. You can view an example on this JSFiddle link. When programmatically ...