Tips on identifying and handling errors without the need for type assertions in this code segment

My code is correct, but it's becoming difficult to maintain...

interface FuncContainer<F extends (..._: Array<any>) => any> {
  func: F
  args: Parameters<F>
}

const func: FuncContainer<typeof Math.min> = {
  func: Math.min,
  args: [3, 4]
}

console.log(func.func(...func.args))


const funcs: Array<FuncContainer<(..._: Array<any>) => any>> = [
  {
    func: Math.min,
    args: [1, 2]
  } as FuncContainer<typeof Math.min>,
  {
    func: fetch,
    args: ["https://google.com"]
  } as FuncContainer<typeof fetch>
]

console.log(funcs)

Everything compiles without errors. However, the issue arises when dealing with Array<FuncContainer>. I want to be able to store different functions with varying parameter signatures in a single array, so I opted for a generic function. I also need TypeScript to ensure that the types within each array element are consistent. To achieve this, I used type assertions within each specific array element, but this method is prone to errors since there's no indication if a type assertion is missed for a new element in an Array<FuncContainer>. Without the required assertion, incorrect argument types won't be detected.

const funcs2: Array<FuncContainer<(..._: Array<any>) => any>> = [
  {
    func: Math.min,
    args: ["5", "6"] // should trigger an error, but it doesn't
  }
]

Is there a more efficient way to annotate the array to enforce type checking for the actual type within each position while eliminating the need for manual type assertions like in the provided example? Perhaps utilizing mapped types?

EDIT: I changed unknown to any to make it compatible with the playground environment

Answer №1

To simplify this process (from a developer experience perspective), it is best accomplished using a function helper:

function funcContainer<F extends (...args: any[]) => any>(func: F, args: Parameters<F>) {
    return {func, args};
}

const funcs = [
    funcContainer(Math.min, [1, 2]),
    funcContainer(fetch, ["https://google.com"]),
    funcContainer(Math.min, ["x"]), // <== Error as desired
];

console.log(funcs);

Try it out here

Additionally, you not only benefit from type safety within the arguments list, but also receive argument suggestions in IDEs that extract information from TypeScript (such as VS Code):

https://i.stack.imgur.com/D2ARO.png

Answer №2

Expanding on the response from @T.J. Crowder: I present a solution that makes use of a single versatile function.

function generateFunctions<
  F extends ((...args: any[]) => any)[]
>(funcs: [...{ [K in keyof F]: [F[K], Parameters<F[K]>] }]) {
    return funcs;
}

const funcs = generateFunctions([
    [Math.min, [1, 2]],
    [fetch, ["https://google.com"]],
    [Math.min, ["x"]], // <== This line should trigger an error
]);

Check it out on the TypeScript Playground

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

I am facing an issue with Nestjs where it is unable to resolve my dependency, despite the fact that it is readily available within the

Encountering the following error: Error: Nest is unable to resolve dependencies of the CreateGroupTask (TaskQueueService, GroupsService, ?, GroupNotificationsService, GroupRepository, Logger). Please ensure that the argument dependency at index [2] is avai ...

`I'm having difficulty transferring the project to Typescript paths`

I posted a question earlier today about using paths in TypeScript. Now I'm attempting to apply this specific project utilizing that method. My first step is cloning it: git clone <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cf ...

Error message: Typescript and Styled-Component conflict: GlobalStylesProps does not share any properties with type { theme?: DefaultTheme | undefined; }

I've encountered an issue while passing props inside GlobalStyles in the preview.js file of my storybook. The props successfully remove the background from the default theme, but I'm receiving an error from Typescript: The error message states " ...

Debugging with Typescript in Visual Studio Code

I attempted to use the solution found here: how to debug typescript files in visual studio code However, when I set a breakpoint in my .ts files, the debugger indicates that the file is not found. Oddly enough, breakpoints in the .js files are working fin ...

Is it possible to build a Node.js (Express) application using a combination of JavaScript and TypeScript?

Currently, I have a Node.js project (Express REST API) that is written in JavaScript. My team and I have made the decision to gradually rewrite the entire project into TypeScript. Is it possible to do this incrementally, part by part, while still being ab ...

404 Error message encountered across all routes in a Node TypeScript Azure Function App - Resource not located

I keep encountering a 404 Not Found error on all routes while requesting my API. I am struggling to correctly write the code. Here's an example of my code: host.json: { "version": "2.0", "extensions": { & ...

Troubleshooting TS Errors in Vue 3 and Vite with Typescript Integration

Currently experimenting with Vue 3, Vite, and TypeScript to build a Vue project. The configuration process has proven to be quite challenging. Despite consulting various documentation sources, I have not been successful in achieving my desired outcome. My ...

Incorporating a Symbol into a Function

Reviewing the following code snippet: namespace Add { type AddType = { (x: number, y: number): number; }; const add: AddType = (x: number, y: number) => { return x + y; }; } Can a 'unique symbol' be added to the AddType lik ...

The type '{}' does not contain a property named 'map'

Recently delving into TypeScript, and I'm curious about the process of typing an axios response when storing it in a state variable. I've initiated a basic API call from App.tsx, which returns the following object: {data: {…}, status: 200, s ...

Trouble accessing images from database in Angular 2 with Firebase

Recently, I've integrated an image upload feature for my database using the following function: private saveFileData(upload: Upload): void { this.firebaseAuth.authState.subscribe(auth => { this.db.list(`uploads/${auth && auth.email && au ...

A better choice than Java's <? super SomeType> in Typescript

Is there a scenario in which one of the generic parameters used to create an instance of my class should be a superclass of another class? In Java, this is easily achievable using <? super SomeType>. What would be the equivalent in TypeScript? ...

Does the routing in Angular 2 get disrupted by parameter breaks in sub-modules?

In my Angular 2 application, I am encountering an issue with routing to my line module. Currently, I have two submodules - login and line. The routing to the login submodule is working well. However, when I attempt to route to the line module with route pa ...

Expect a reply within the loop

One of my endpoints takes some time to generate data, and I have another endpoint to retrieve that generated data. I make the initial call using await, extract the ID from the response, and then keep calling the second endpoint until the status is not "Suc ...

Modifying data types within complex nested object structures

I am looking to traverse the data structure recursively and create a custom type with specific fields changed to a different type based on a condition. Using the example structure below, I aim to generate a type (Result) where all instances of A are repla ...

The parameter type 'void' cannot be assigned to the parameter type 'SetStateAction<{}>'

Currently, I am in the process of developing an application utilizing TMDB with NextJS and Typescript. Within my movies.ts file, I have implemented the following code: export async function getTrendMovies() { const url = 'https://api.themoviedb.o ...

Expanding the Window Object in Typescript with Next.js Version 13

Within my Next.js 13 project, I am looking to enhance the Window object by adding a property called gtag I created an index.d.ts file in the root folder with the following content: index.d.ts declare module '*.svg' { const content: any; exp ...

The "in operator" is not compatible with string indexes

Unique Code const example = { one: 'two', three: 'four', }; const keyToRetrieve: string = 'one'; if (keyToRetrieve in example) { console.log(example[keyToRetrieve]); // output: "two" (No Error) } Removing as const doe ...

Having trouble importing the Renderer2 component in Angular

Trying to include Renderer2 with the following import: import { Renderer2 } from '@angular/core'; Encountering an error: "Module 'project/node_modules/@angular/core/index' does not have an exported member 'Renderer2'. Puzz ...

Looping through the json resulted in receiving a null value

When working with typescript/javascript, I encountered an issue while trying to fetch the 'statute' from a data object: {_id: "31ad2", x: 21.29, y: -157.81, law: "290-11",....} I attempted to assign data.law to a variable, but received a typeer ...

React classes with external scripts

I'm currently working on embedding an external map service into my React application. The recommended way to integrate the API into a regular HTML web page is shown below: <script type="text/javascript" src="//map.search.ch/api/map.j ...