An array in Typescript comprising a variety of generic types

My aim with TypeScript is to generate an Array containing different generics.

The purpose of my generic class is to define table columns, with T representing the type of values the column will contain. The structure is like this:

export class TableColumnConfig<T> { ... }

When adding multiple columns to a table, I follow these steps:

const columns: TableColumnConfig<any>[] = [];

Subsequently, I do something along the lines of:

columns.push(new TableColumnConfig<number>());
columns.push(new TableColumnConfig<string>());

This implementation works effectively, but there's a note from eslint advising against the use of any

Unexpected any. Specify a different type.eslint@typescript-eslint/no-explicit-any

Eslint recommends using unknown.

To adhere to this recommendation, I make the adjustment here:

const columns: TableColumnConfig<unknown>[] = [];

However, this leads to the following error:

Argument of type 'TableColumnConfig<number>' is not assignable to parameter of type 'TableColumnConfig<unknown>'. Type 'unknown' is not assignable to type 'number'.ts(2345)

Is there a solution that satisfies both eslint and avoids TypeScript syntax errors?

Would it be acceptable in this scenario to ignore eslin'ts warning?

Your insights and guidance are greatly appreciated! :)

EDIT: This is how my class and the builder that I use for it looks like:

export class TableColumnConfig<T> {

    // lots of properties (that don't utilize T)

    format?: (val: T) => string;
    sort?: (val1: T, val2: T) => number;

    constructor() {
        // ...
    }
}

export class TableColumnConfigBuilder<T> implements ITableColumnConfigBuilder<T> {
  private tableColumnConfig: TableColumnConfig<T>;

  constructor() /* some mandatory properties */
  {
    this.tableColumnConfig = new TableColumnConfig(
      sourceAddress,
      parameterAddress,
      dataType,
      mainLabel
    );
  }

  // ...

  setFormat(format: (val: T) => string): this {
    this.tableColumnConfig.format = format;
    return this;
  }
  setSort(sort: (val1: T, val2: T) => number): this {
    this.tableColumnConfig.sort = sort;
    return this;
  }

  get(): TableColumnConfig<T> {
    return this.tableColumnConfig;
  }
}


interface ITableColumnConfigBuilder<T> {
    // ...
  setFormat(format: (val: T) => string): this;
  setSort(sort: (val1: T, val2: T) => number): this;
}

Answer №1

The issue you're encountering is associated with variance. The functions format and sort have a contravariant use of type T, which makes the TableColumnConfig type contravariant as well, leading to reversed assignability. There may also be other properties in TableColumnConfig that are in a covariant position, ultimately resulting in an invariant type.

To resolve this error, opt for using methods instead of properties with functions. I discovered today that methods can also be optional.

export class TableColumnConfig<T> {

    format?(val: T): string
    sort?(val1: T, val2: T): number

    constructor() {}
}

const columns: TableColumnConfig<unknown>[] = [];

// no issues arise now
columns.push(new TableColumnConfig<number>());
columns.push(new TableColumnConfig<string>());

This approach works because method variance operates differently. Refer to this link for more information.

Method types both co-vary and contra-vary with their parameter types


Playground

Answer №2

To ensure that the type of columns accurately reflects the types of the columns it contains, you can do the following:

const columns: (TableColumnConfig<number> | TableColumnConfig<string>)[] = [];
// −−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Testing link

If you define columns with a literal and omit an explicit type, TypeScript will automatically infer the correct types for you:

const columns = [
    new TableColumnConfig<number>(),
    new TableColumnConfig<string>(),
];

Testing link

However, this approach may not always be feasible.


If precision in type is not crucial, you can use any as a flexible alternative.

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

Exploring the world of Java generics, stretching the boundaries with extended generics, and del

In my setup, I have the following classes: public abstract class Process<T,S> { ... } public abstract class Resource<T, S extends Process<T, S>> { protected S processor; ... } public class ProcessImpl<EventType1, EventTy ...

Automatically injecting dependencies in Aurelia using Typescript

Recently, I started working with Typescript and Aurelia framework. Currently, I am facing an issue while trying to implement the @autoinject decorator in a VS2015 ASP.NET MVC 6 project. Below is the code snippet I am using: import {autoinject} from "aure ...

Collaborate and apply coding principles across both Android and web platforms

Currently, I am developing a web version for my Android app. Within the app, there are numerous utility files such as a class that formats strings in a specific manner. I am wondering if there is a way to write this functionality once and use it on both ...

Problem with saving LokiJS database to persistence

For my current project, I have been utilizing lokijs on node alongside express, socket, and typescript. Recently, I encountered an issue where I have two instances of loki database and when attempting to use db.saveDatabase(), it does not save the changes ...

Steps for transforming 112889 (in mmddyy format) into 11/28/89 or 11/28/1989

Is there a way to convert the unformatted date 112889 (mmddyy) into a specific format like 11/28/89? console.log(new Date('112889')) // The output I'm getting is: Sat Jan 01 112889 00:00:00 GMT+0800 I've searched extensively on Google ...

What is the method for extracting only TypeScript types from the threeJs package?

I am in the process of developing a front-end application using Webpack with threeJs functionality integrated. Previously, I would refrain from bundling threeJs to keep the size small by utilizing the threeJs UMD from a CDN link in my index.html file. Desp ...

Incorporating Google Pay functionality within Angular applications

I have been attempting to incorporate Google Pay into my Angular project, but I am struggling to find reliable resources. My main issue revolves around the following code... <script async src="https://pay.google.com/gp/p/js/pay.js" onloa ...

What is the process of transforming a jQuery element into a TypeScript instance?

In TypeScript, I am working with an object called DataTable that contains multiple methods, one of which is 'refresh' To display this DataTable on the page, it is structured as follows <table class='DataTable'>...</table> ...

Having trouble with the rowNode functionality in PrimeNG TreeTable

I am currently utilizing the PrimeNG Treetable component from https://www.primefaces.org/primeng/#/treetable I seem to be encountering issues with retrieving data from the service. Below is a snippet of my code: HTML <p-treeTable [value]="temp"> & ...

Discovering the Solution: Angular 17's Answer to Troubleshooting Peer Dependency Conflicts

After upgrading Angular to version 17 using npm --force, my application was running smoothly in a local environment. However, when attempting to deploy it (via octopus deploy), the npm install process was automatically triggered by .Net, resulting in a lis ...

What is the best way to retrieve the current height in VueJS using the Composition API?

I am utilizing a Ref to preserve the current height of the active element. My goal now is to transfer this height to the subsequent element that gets clicked on. <script lang="ts" setup> import { ref, reactive } from "vue"; defin ...

Tips on obtaining the current date format (e.g. dd/mm/yyyy or mm/dd/yyyy) on the client side

I am currently working with the datepicker control, and I need to adjust the date format based on my browser's settings - either dd/mm/yyyy or mm/dd/yyyy. For example: if my browser date is 22/06/2019, then I should use "dd/MM/yyyy" format in the dat ...

Add a class to a button in an Angular btn-group if a specific string is found within an

I am currently working on a project where I have multiple buttons that need to toggle an active class when selected in order to change their color. Below is a snippet of what I have: In the array called 'selected', I have: this.selected = [&ap ...

When multiple tabs of a Chrome extension are opened, the onMessage.addListener in the service worker is triggered twice for each tab

Whenever I have two or more of my extension tabs open, the functions chrome.runtime.sendMessage and chrome.runtime.onMessage.addListener seem to run twice. However, when I only have one tab open, everything works fine. What could be causing this issue and ...

What is the best way to enable swipe functionality for ion-items in Ionic without requiring a click?

I have been working on implementing an ion-list with swipable ion-items that do not need to be clicked on the side to trigger an event. The functionality I am aiming for is similar to the default contacts app on Samsung phones, where a left swipe calls an ...

When you click, you will be directed to the specific details of the object

I have a recipe component that displays a list of recipes from my database and a recipe-detail component that should show the details of a selected recipe. What I aim to achieve is that when someone clicks on a recipe name, they are routed to the recipe-de ...

Streamlining all icons to a single downward rotation

I am currently managing a large table of "auditpoints", some of which are designated as "automated". When an auditpoint is automated, it is marked with a gear icon in the row. However, each row also receives two other icons: a pencil and a toggle button. W ...

It appears there was a mistake with [object Object]

Hey there, I'm currently working with Angular 2 and trying to log a simple JSON object in the console. However, I keep encountering this issue https://i.stack.imgur.com/A5NWi.png UPDATE... Below is my error log for reference https://i.stack.imgur.c ...

Guide on creating a style instance in a component class using Material-UI and Typescript

After transitioning my function component to a class component, I encountered an error with makeStyle() from Material-UI as it violates the Rule of Hooks for React. The documentation for Material-UI seems to focus mainly on examples and information related ...

the input parameter is not being passed to the component

I need assistance with creating an inline input edit component. The component is loading correctly, but it seems like the @Input() variables are always returning undefined. index.html ... <app-inlineinput [name]="username" [fi ...