TypeScript's reliance on dependent types

Is it possible to implement this functionality using TypeScript?

There exist objects that define various "actions".

export interface IAction {
    action: string;
    data: any;
    otherParam1: number;
    otherParam2: number;
}

The 'action' property is a string with a predefined set of values ("one", "two", "three" for example). Each action has different data format associated with it.

export interface IActionOneData {
    x: number;
}
export interface IActionTwoData {
    y: number;
    z: string;
}
export interface IActionThreeData {
    someList: Array<string>;
}

The intention is to handle actions based on their specific data formats (e.g. if action is "one", then use "one-format").

function doAction(action: IAction): void {
    if (action.action === "one") {
        console.log("x = " + action.data.x);
    }
    // ...
}

My initial approach (which isn't functioning as expected):

export enum ActionTypes {
    one = "one",
    two = "two",
}

export interface IAction {
    action: ActionTypes;
    data: any;
    otherParam1: number;
    otherParam2: number;
}

export interface IActionOneData {
    x: number;
}

export interface IActionOne extends IAction {
    action: ActionTypes.one;
    data: IActionOneData;
}

function doAction(action: IAction): void {
    if (action.action === ActionTypes.one) {
        console.log("x = " + action.data.undef); // no error, data is any
    }
    // ...
}

Answer №1

Utilizing discriminated unions for a solution (opting not to speculate on its superiority). Special thanks to @captain-yossarian hailing from Ukraine

export enum ActionTypes {
    uno = "uno",
    dos = "dos",
}

export interface IActionBase {
    action: ActionTypes;
    data: any;
    otherParam1: number;
    otherParam2: number;
}

export interface IActionUnoData {
    x: number;
}
export interface IActionDosData {
    y: number;
    z: string;
}
export interface IActionTresData {
    someList: Array<string>;
}

export interface IActionUno extends IActionBase {
    action: ActionTypes.uno;
    data: IActionUnoData;
}
export interface IActionDos extends IActionBase {
    action: ActionTypes.dos;
    data: IActionDosData;
}

type IAction = IActionUno | IActionDos;

function performAction(action: IAction): void {
    if (action.action === ActionTypes.uno) {
        console.log("x = " + action.data.x);
    } else if (action.action === ActionTypes.dos) {
        console.log("y = " + action.data.y);
    }
    // ...
}

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

In a functional component in Typescript, what data type should be used for a parameter that accepts an array of objects?

const FormData = ({ dataArray }: object[]): JSX.Element => { console.log("Array of Objects",dataArray) //This is a large form component.... }); The dataArray contains multiple objects, how can I specify a specific type for these components ...

Error: Trying to modify an immutable property 'title' of object '#<Object>' - React JS and Typescript

Whenever I press the Add button, all input values are stored in a reducer. However, if I append any character to the existing value in the input fields, it triggers the following error: Cannot assign to read only property 'title' of object &apos ...

In React Typescript, the input type="checkbox" does not show any value in the value attribute

I'm facing an issue with displaying text next to a checkbox in React Typescript. When I try to use the value attribute, it doesn't seem to work as expected. Also, attempting to set innerHTML throws an error stating that input is a void element ta ...

Struggling to create an Extension Method for Map<TKey, TValue[]> in TypeScript

As a new Angular/TypeScript user, I am really enjoying using Extension methods. They work well on standard types, but now I am facing an issue while trying to write one for the Map data structure where values are arrays. Unfortunately, it does not seem to ...

Is there a way to efficiently convert several strings within an object that has been retrieved from an HTTP request into another language, and subsequently save this object with the

Is there a way for me to translate some strings in an object before storing it in another http request using the Google Translate API? I am currently getting the object from one http request and saving it with a put method. How can this be achieved? servi ...

Ensuring that files adhere to the required format, whether they be images

Three separate input fields are being used, each with its own name for identification. A validation method is called to ensure that the files selected in these input fields are not duplicates and that they are either images or PDFs but not both. While thi ...

Using Checkboxes in React with Material-UI

I am currently facing an issue with my 2 checkboxes. Whenever I select one, both of them get selected automatically. I want the user to be able to choose one, both, or none at all. It's puzzling why they are both getting selected simultaneously. Here ...

Ways to effectively utilize an interface incorporating props.children and other property varieties

Currently working on a project with Next.js and Typescript. In order to create a layout component, I defined the following interface: export interface AuxProps { children: React.ReactNode; pageTitle: 'string'; } The layout component code sn ...

Is there a way to utilize an Event Emitter to invoke a function that produces a result, and pause until the answer is provided before continuing?

Looking for a way to emit an event from a child component that triggers a function in the parent component, but with a need to wait for a response before continuing. Child @Output() callParentFunction = new EventEmitter<any>(); ... this.callParen ...

Having trouble assigning a value of `undefined` to a TextField state in React hook

I am in need of setting the initial state for a TextField date to be undefined until the user makes a selection, and then allowing the user an easy way to reset the date back to undefined. In the code snippet below, the Reset button effectively resets par ...

Learn how to easily set a radio button using Angular 4 and JavaScript

It seems like a simple task, but I am looking for a solution without using jQuery. I have the Id of a specific radio button control that I need to set. I tried the following code: let radiobutton = document.getElementById("Standard"); radiobutton.checke ...

What could be causing this function to malfunction?

Apologies for any inaccuracies in technical terms used here. Despite being proficient in English, I learned programming in my native language. I am currently working on a project using the latest version of Angular along with Bootstrap. I'm unsure if ...

Enhance the annotation of JS types for arguments with default values

Currently, I am working within a code base that predominantly uses JS files, rather than TS. However, I have decided to incorporate tsc for type validation. In TypeScript, one method of inferring types for arguments is based on default values. For example ...

Customizing number input types in Angular 2 - the perfect solution

Attempting to incorporate a time picker using HTML5 input type number in Angular2. The code snippet below illustrates the setup: <input type="number" [(ngModel)]="hour" (change)="checkHours();" name="one" min="1" max="12"> <input type="number" ...

Is the ID Column in the Minimal Material Table Demo not appearing as expected?

Hey there, I'm in the process of developing a simple demonstration of a material table - Take note that this is a stackblitz link and for some reason, the id column isn't showing up. Here's a snippet from my app.component.ts: import { C ...

The BooleanField component in V4 no longer supports the use of Mui Icons

In my React-Admin v3 project, I had a functional component that looked like this: import ClearIcon from '@mui/icons-material/Clear' import DoneIcon from '@mui/icons-material/Done' import get from 'lodash/get' import { BooleanF ...

Guide to adding information to a table with the help of an "interface" in Angular 6 and utilizing Typescript

Looking for some guidance with Angular as I am just starting out. I am currently trying to send an API request in angular 6 using Typescript. However, I am facing difficulties when it comes to adding data to a table. Check out my code on: Codepen In my p ...

Combining data from various API calls into one cohesive array using RXJS

My RXJS Pipeline is structured as follows: const logs: number[] = [1, 2, 3, 4]; const url = 'http://some-url-here.com'; const pipeline = from(logs).pipe( switchMap(logId => this.callEndpoint(url, logId).pipe(map(response => response. ...

Tips for building and implementing Angular URL Parameters for URLs in the form: "component/#/?id=..."

I am currently facing a situation where I have an application with an existing user base. I am looking to avoid disrupting their current links for a smoother transition. However, the previous links are in this format: (server)/viewer/#/?id=12. Please see t ...

Converting constants into JavaScript code

I've been diving into typescript recently and came across a simple code snippet that defines a constant variable and logs it to the console. const versionNuber : number = 1.3; console.log(versionNuber); Upon running the tsc command on the file, I no ...