Challenge with enforcing strong typing in Typescript

Here is the code snippet that I am working with:

export type FooParams = {
  foo1: { x: number };
  foo2: { y: string };
};

export type FooKey = keyof FooParams; // or export type FooKey = "foo1" | "foo2";

export interface FooAction<T extends FooKey> {
  execute: (params: FooParams[T]) => void;
}

const foo1Action: FooAction<"foo1"> = {
  execute: (params) => {
    console.log(params.x);
  },
};

const foo2Action: FooAction<"foo2"> = {
  execute: (params) => {
    console.log(params.y);
  },
};

export const fooActions: Record<FooKey, FooAction<FooKey>> = {
  foo1: foo1Action,
  foo2: foo2Action,
};

I am facing an issue where I cannot strongly type the variable fooActions to ensure a FooAction for every FooKey. The error message in this example points out the following problem.

Type 'FooAction<"foo1">' is not assignable to type 'FooAction<keyof FooParams>'.
  Type 'keyof FooParams' is not assignable to type '"foo1"'.
    Type '"foo2"' is not assignable to type '"foo1"'.ts(2322)

If you have any suggestions on how to correctly declare the type of fooActions, please let me know!

Answer №1

FooAction<FooKey> defines that execute will be of type

(params: FooParams[FooKey]) => void
, resulting in
(params: { x: number } | { y: string }) => void;
. This requires a function that can handle both { x: number } and { y: number }. Therefore, all values in an object of type
Record<FooKey, FooAction<FooKey>>
must manage both types, while foo1Action and foo2Action can only handle one type each.

To associate keys with types in typing fooActions, a custom mapped type can be used:

type FooActionMap = {
    [P in FooKey]: FooAction<P>
}
export const fooActions: FooActionMap  = {
  foo1: foo1Action,
  foo2: foo2Action,
};

Playground Link

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

Failure in Testing: ReferenceError indicating that SpeechSynthesisUtterance has not been defined

In a recent project, I decided to add text-to-speech functionality and opted for a plain JavaScript solution. (https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance) Currently, I am using [email protected] and [email protecte ...

Angular 9: The instantiation of cyclic dependencies is not allowed

After transitioning from Angular 8 to Angular 9, I encountered an issue with a previously functioning HTTP communication service. The error message now reads: Error: Cannot instantiate cyclic dependency! HttpService at throwCyclicDependencyError (core ...

Navigating Unpacked Varied Tuple Types

Here is the code snippet to consider: interface Wrap<Value> { pick(): Value } class WrapConstant<Value> implements Wrap<Value> { constructor(public readonly a: Value) { } pick(): Value { return this.a } } type Unwrap<Wrapped> ...

When attempting to fetch JSON data using the Angular 2 `http.get()` method, the data returned is undefined and the component does not reflect any

My http-data.service is set up to accept json for output in the component template. Initially, the console displays that the first few calls return undefined, while subsequent calls start returning json. However, upon checking the component, it is evident ...

Troubleshooting a NextJs/TS problem with importing ESM modules

Click here for the Code Sandbox I'm currently in the process of transitioning some code to NextJS 11 / Webpack 5, including certain modules that now exclusively support ECMAScript Modules (esm). Prior to the upgrade, I could easily export all files ...

Spread operator in TypeScript does not interact properly with a specific type

Currently, I am working with a redux-style reducer in ngrx that returns a specific type. However, I have encountered an issue where the TypeScript linter fails to catch invalid properties when using the spread operator in my return object. Below is the in ...

The function Keyboard.hide() is ineffective when used in a project built with capacitor or ionic 6

In my app, there is a simple form where users can input two values and have them added together. Below is the code for my form: <form (ngSubmit)="calculateTwo(value1, value2)"> <ion-grid> <ion-row> <ion-co ...

Issue with TypeScript Functions and Virtual Mongoose Schema in Next.js version 13.5

I originally created a Model called user.js with the following code: import mongoose from "mongoose"; import crypto from "crypto"; const { ObjectId } = mongoose.Schema; const userSchema = new mongoose.Schema( { //Basic Data ...

Use TypeScript to cast the retrieved object from the local storage

const [savedHistory, setSavedHistory] = useState(localStorage.getItem('history') || {}); I'm facing an issue in TypeScript where it doesn't recognize the type of 'history' once I fetch it from localStorage. How can I reassign ...

There was an unhandled rejection error stating: "TypeError - Unable to access property 'push' as it is undefined"

I am encountering an issue while trying to create a function that returns all indexes of an array. I'm not sure what mistake I might be making, as I keep getting an error stating that push cannot be used due to an undefined value. Here's the cod ...

Angular2 Meteor app encounters difficulty locating basic types in Typescript

Every time I try to use Date, I encounter the following error during compilation: 'Date' cannot be found Here is an example of how it is used: var pastEvents = Events.find({ timestamp: { $lt: new Date() }}); Points to Note: The same issu ...

What could be causing my child component to not receive an update in state from its parent component?

Scenario My goal is to utilize google-map-react to display nearby bakery stores. However, when I include the line console.log(props); in my child component StoresGoogleMap, it shows storeLocations and stores as []. By using the following code snippet in ...

Best practices for utilizing dotenv / .env to pass parameters in typescript

I am currently working on a typescript application in VS Code and have moved sensitive information to a .env file: # .env file NAME='foobar' Within my main app, which utilizes the .env file, I have included the dotenv npm package. Additionally, ...

Passing parameters in Angular routes may result in routes not being able to match

I am facing an issue while trying to access a component that requires 2 URL parameters. Despite providing the parameters, I encounter an error indicating that the routes cannot be matched. const routes: Routes = [ { path: 'home', componen ...

What is the best way to create an "ArraySimilar" class using TypeScript?

Can someone guide me on creating an ArrayLike class in TypeScript? Edit: Got the solution from @jcalz, it's working perfectly for me. class CustomArray<T> implements ArrayLike<T> { length: number [index: number]: T } ...

Creating a Typescript union array that utilizes a string enum for defining key names

Can we shorten this statement using string enum to restrict keys: Array<{ [enum.example1]: Example } | { [enum.example2]: Example } | ...> // or equivalent ({ [enum.example1]: Example } | { [enum.example2]: Example } | ...)[]; We can make it more c ...

How to jest at node_modules that provide a function?

I've been working on a typeScript program that interacts with an external API. While writing tests for this program, I've encountered challenges in properly mocking the dependency on the external API to analyze the values passed to the API itself ...

Using JavaScript, generate an array of objects that contain unique values by incrementing each value by 1

I have an array of objects called arrlist and a parameter uid If the property value has duplicate values (ignoring null) and the id is not the same as the uid, then autoincrement the value until there are no more duplicate values. How can I achieve the a ...

What is the best way to convert this into a distinct function using typescript?

Is there a way to create a single method in Protractor or Webdriver API that can get the browser width and height? const getWindowWidth = async () => { const size = await browser.manage().window().getSize(); return size.width; }; I need this metho ...

What are some effective methods for implementing push notifications in a ionic4-5 project?

Seeking advice on the most effective method for implementing push notifications in an Ionic 4-5 project (Angular 4-5, Typescript) for both iOS and Android devices. Also looking for a comprehensive resource that includes all necessary information to success ...