TypeScript array containing elements of various types

Looking to achieve something along these lines:

type Element<S> = S & {
  action: (v: S) => void
}

function b<What>(...elements: Element<What>[]) {}

b({
  title: "",
  action: (v: {title: string}) => {}
}, {
  number: 0,
  action: (v: {number: number}) => {}
})

The code above is giving an error, any suggestions on how to accomplish a similar task using TypeScript?

Answer №1

You have the option to utilize a syntax similar to this:

function customizedFunction<T extends any[]>(...items: { 
  [K in keyof T]: T[K] & { description: (v: Omit<T[K], 'description'>) => void } 
}) {}

In this case, a mapped type is employed to iterate over each element in items. The representation of T[K] always reflects the current element, enabling us to intersect it with the function object.

// valid
customizedFunction({
  name: "",
  description: (v: { name: string }) => {}
}, {
  count: 0,
  description: (v: { count: number }) => {}
})

// invalid
customizedFunction({
  name: 0,
  description: (v: { name: string }) => {} /*
  ~~~~ Types of property 'name' are incompatible 
*/ 
}, {
  count: 0,
  description: (v: { count: number }) => {}
})

When implementing the function, it is advisable to encapsulate all the intricate generic aspects in an overload and adopt a simpler signature for the implementing function.

function implementationFunc<T extends any[]>(...items: { 
  [K in keyof T]: T[K] & { description: (v: Omit<T[K], 'description'>) => void } 
}): void
function implementationFunc(...items: ({ description: (arg: object) => void } & Record<string, any>)[]) {
  for (const item of items) {
    item.description({})
  }
}

Interactive Tool

Answer №2

Close to finding the solution, but struggling with auto-inferencing the generic function. Sharing my progress in case it helps someone else crack it or provides some insights.

The approach I took was to recursively infer each Item within What, ensuring that What is treated as a tuple and the Item constraint is applied individually to each element in What.

type Item<T> =
    T & {func(v:T):void}

type Items<What> =
    What extends [Item<infer A>, ...infer Rest]
    ? [Item<A>,...Items<[...Rest]>]
    : What extends [] ? [] : never

function testFunction<What>(...items: Items<What>) {}

//this works, with an explicit generic
testFunction<[Item<{
    name: string;
}>, Item<{
    count: number;
}>]>({
  name: "",
  func: (v: {name: string}) => {}
}, {
  count: 0,
  func: (v: {count: number}) => {}
})

Playground

Answer №3

interface Element<E> = E & {
  action: (e: E) => void
}

function processElements<T extends Element<any>[]>(...elements: T) {}

processElements({
  name: "",
  action: (e: {name: string}) => {}
}, {
  count: 0,
  action: (e: {count: number}) => {}
})
// ^?
// function processElements<[{
//     name: string;
//     action: (e: {
//         name: string;
//     }) => void;
// }, {
//     count: number;
//     action: (e: {
//         count: number;
//     }) => void;
// }]>(element_0: {
//     name: string;
//     action: (e: {
//         name: string;
//     }) => void;
// }, element_1: {
//     count: number;
//     action: (e: {
//         count: number;
//     }) => void;
// }): void

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

Angular 2/4 throws an Error when a Promise is rejected

I implemented an asynchronous validator function as shown below. static shouldBeUnique(control: AbstractControl): Promise<ValidationErrors | null> { return new Promise((resolve, reject) => { setTimeout(() => { if (contr ...

What is the process for adding new methods to a predefined data type?

Currently, I am utilizing Webpack's require.context in order to eliminate redundancy while importing multiple pages. However, TypeScript is throwing an error stating that Property 'context' does not exist on type 'NodeRequire'.. I ...

Obtaining a Comprehensive Response (not limited to just the body) through Angular 4 HTTP Requests

I am currently working on getting a full response from my HTTP calls. Following the guidelines in the Angular documentation, I have set my HTTP call options as {observe: 'response'} However, when I implement this, I encounter the following error ...

Struggling with TypeScript errors when using Vue in combination with Parcel?

While running a demo using vue + TypeScript with Parcel, I encountered an error in the browser after successfully bootstrapping: vue.runtime.esm.js:7878 Uncaught TypeError: Cannot read property 'split' of undefined at Object.exports.install ...

Kindly include an @Ionic3Annotation for either @Pipe, @Directive, or @Component

During development, this code runs without any issues. However, when attempting to run it in production using the command: Working: ionic cordova run android Not working: ionic cordova run android --prod --release Error Message: [03:34:41] types ...

What is the best way to access data from a local JSON file in Gatsby when using TypeScript and GraphQL?

I'm updating my former gatsby site using TypeScript. I encountered an issue while trying to retrieve data from a local JSON file: There appears to be an error in your GraphQL query: Cannot find field "allNavigationLinksJson" on type "Q ...

Issue encountered with express-jwt and express-graphql: TypeScript error TS2339 - The 'user' property is not found on the 'Request' type

Implementing express-jwt and graphql together in typescript has been a challenge for me. import * as express from 'express' import * as expressGraphql from 'express-graphql' import * as expressJwt from 'express-jwt' import s ...

Angular Routing can be a powerful tool for managing multiple article posts in an efficient and organized way

I am in the process of building a website with Angular that features numerous articles. Whenever a user clicks on an article, I want it to navigate to a new URL using routing. To achieve this, I have created a new Article component and here is how my app- ...

Implementing User Role-based Access Control in Firebase - Troubleshooting Error with switchMap

I am currently working on implementing Role-Based User Access Control With Firebase in order to grant access to a route only if the user is authenticated and has admin privileges. I am following this tutorial for guidance: My AuthService import { Injecta ...

What is the method for choosing an element by class name in TypeScript?

Currently, I'm working on creating a responsive menu bar that collapses on smaller screens. The challenge I'm facing is that I'm using TypeScript for this project. Is there any guidance on how to translate the following code into TypeScript? ...

assign a random name to the "attribute" of any object

I recently started using TypeScript and I have a question about the syntax. I came across some code that defines a parameter like this: { [property: string]: any} I'm a bit confused because I understand that the parameter should be an object and its ...

Guide to incorporating third-party libraries in Angular

Greetings, I have a common question regarding Angular and utilizing third-party libraries. As someone who does not frequently work with Typescript/Frontends, I am encountering an issue with Angular. Specifically, I am attempting to incorporate the node-htm ...

Retrieving the latest status array by index using Typescript in Angular

Need help with this code logic. I am working on an array and function : import { Component } from '@angular/core'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.compon ...

Is it possible in TypeScript to convert a nested ternary into a standalone statement?

I encountered an error while working with the code snippet provided below. As I am relatively new to nested ternary operations, I would appreciate any assistance you could provide. Here is the example code: get notEmptyProduct(): string[] { return th ...

Issues with NativeScript WebView displaying HTML file

Having trouble loading a local HTML file into a webview in my NativeScript (typescript) application. Despite using the correct path, it's not loading and instead shows an error. <WebView src="~/assets/content.html" /> An error message stati ...

Destructuring an array of strings for use as parameters

Hey guys, I'm working with an array of keys here Example 1: let keyArray = ['x', 'y', 'z'] I'm trying to find a way to use these keys as parameters without repeating them multiple times. Do you have any suggestions ...

The search for d.ts declaration files in the project by 'typeRoots' fails

// Within tsconfig.json under "compilerOptions" "typeRoots": ["./@types", "./node_modules/@types"], // Define custom types for Express Request in {projectRoot}/@types/express/index.d.ts declare global { namespace Express { interface Request { ...

Angular 6 offers a versatile multi-select dropdown feature

Looking to select multiple values in Angular 6 using checkboxes. When selecting a department from the dropdown, a list of employees related to that department is displayed in another dropdown with checkboxes. However, only the last value of the array app ...

Is it considered poor practice to specify the type explicitly when it can be easily inferred by Tslint?

When using VSCode, the linter tslint may raise an issue when the following code is added with a specific type: serverId: number = 10; This will trigger the following message: [tslint] Type number trivially inferred from a number literal, remove type ...

IE11 is throwing a fit because of a pesky long-running script error caused by the powerful combination of Webpack, React,

Utilizing webpack 4.* for bundling my react 16.* and typescript 3.* project has been causing issues on internet explorer 11. I consistently encounter a "not responding long running script error" on both local and test servers (in production mode). The lac ...