Leveraging two data types for a single variable in Typescript

While transferring js typescript, I encountered a problem. The function below is designed to work with two different types of data, but I am seeing this error:

Property 'dateTime' does not exist on type 'Operation | OperationCreated'. 
Property 'dateTime' does not exist on type 'OperationCreated'

type DateTime = {
  date: string;
};

type Operation = {
  dateTime: DateTime;
};

type OperationCreated = {
  createdDate: string;
};

const sortByDate = (o1: Operation | OperationCreated, o2: Operation | OperationCreated) =>
  stringToMillisecond(o1.createdDate || o1.dateTime.date) - stringToMillisecond(o2.createdDate || o2.dateTime.date);

Just taking the initial steps in typescript, any help would be appreciated

Answer №1

One key issue with TypeScript is its interpretation of

o1.createdDate || o1.dateTime.date
as invalid due to a few reasons:

  • An important concern is that assuming o1.createdDate will only be falsy if it is undefined overlooks the fact that the empty string is also falsy. This oversight can lead to errors, as demonstrated in the example provided. Therefore, relying on a falsy check for potentially string values is not advisable in this context.

  • Furthermore, the TypeScript compiler requires that you narrow down the type of o1 to a specific type, such as OperationCreated, before reading a property value of a union type. This can be achieved by using a type guard mechanism such as the in operator:

    "createdDate" in o1 ? o1.createdDate : o1.dateTime.date; // no error
    

    This method effectively narrows down the type of o1 based on the presence of the "createdDate" property, avoiding potential errors during compilation.

To address these issues, a straightforward solution would be:

const sortByDate = (
  o1: Operation | OperationCreated,
  o2: Operation | OperationCreated
) =>
  stringToMillisecond("createdDate" in o1 ? o1.createdDate : o1.dateTime.date) -
  stringToMillisecond("createdDate" in o2 ? o2.createdDate : o2.dateTime.date);

Hopefully, this explanation clarifies the challenges you encountered. Best of luck with your TypeScript endeavors! Source Code Link

Answer №2

The issue arises from ambiguity in the compiler regarding whether o1 and o2 belong to the Operation or OperationCreated types. To resolve this, consider implementing discriminated unions.

Here's a cleaner solution:

interface DateTime {
  date: string;
}

interface OperationDefault {
  type: 'default';
  dateTime: DateTime;
}

interface OperationCreated {
  type: 'created';
  createdDate: string;
}

type Operation = OperationDefault | OperationCreated;

const sortByDate = (o1: Operation, o2: Operation) => {
  const d1 = o1.type === 'default' ? o1.dateTime.date : o1.createdDate;
  const d2 = o2.type === 'default' ? o2.dateTime.date : o2.createdDate;

  return stringToMillisecond(d1) - stringToMillisecond(d2);
};

Answer №3

Implementing Interfaces for Date and Operation Comparison

    interface DateInterface {
        date: string;
    }

    interface OperationInterface {
        dateTime: DateInterface;
    }

    interface OperationCreatedInterface {
        createdDate: string;
    }

    const sortOperationsByDate = (
        operation1: OperationInterface | OperationCreatedInterface,
        operation2: OperationInterface | OperationCreatedInterface
    ) =>
        stringToMilliseconds((operation1 as any).createdDate || (operation1 as any).dateTime.date) -
        stringToMilliseconds((operation2 as any).createdDate || (operation2 as any).dateTime.date);

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

Tips on using class-validator @isArray to handle cases where only a single item is received from a query parameter

Currently, I am attempting to validate a request using class-validator to check if it is an array. The inputs are sourced from query parameters like this: /api/items?someTypes=this This is what my request dto resembles: (...) @IsArray() @IsEn ...

There was a TypeScript error found at line 313, character 9 in the file @mui/material/styles/experimental_extendTheme.d

Encountering Typescript error while using Material UI component for date range picker Link - https://mui.com/x/react-date-pickers/date-range-picker/ Snippet of the code import * as React from 'react'; import { Dayjs } from 'dayjs'; im ...

Create a package themed with Material UI for export

I am attempting to create a new npm package that exports all @material-ui/core components with my own theme. I am currently using TypeScript and Rollup, but encountering difficulties. Here is the code I have: index.ts export { Button } from '@materia ...

component is receiving an incompatible argument in its props

I am facing a situation where I have a component that works with a list of items, each with an ID, and a filtering function. The generic type for the items includes an ID property that all items share. Specific types of items may have additional properti ...

Error occurred when sending form data while uploading a file

Upon trying to upload a file using the formData.append(key, value);, an error message is displayed in the value section: The argument of type 'unknown' cannot be assigned to a parameter of type 'string | Blob'. Type '{}' is ...

Oops! Looks like an issue has popped up: using require() of an ES module is not supported when using recharts in combination with next.js

I've noticed some similar questions, but none of them seem to address my particular issue. I'm currently working on a webapp using next.js (with typescript). Within the app, I am utilizing recharts, however, I am encountering a compilation error: ...

Guide on switching locales from US to Japan in react-big-calendar

Currently, I am trying to customize a calendar component using the react-big-calendar library. My goal is to localize it for Japan, but I'm facing some challenges. Error Message: Unexpected require(). 'ja' is defined but never used. Code S ...

pnpm, vue, and vite monorepo: tackling alias path imports within a workspace package

I am in the process of creating a monorepo for UI applications that utilize shared components and styles with pnpm, typescript, vue, and vite. While attempting to streamline development and deployment using pnpm's workspace feature, I am encountering ...

What is causing the issue in locating the assert package for VS Code and TypeScript?

My main issue lies with the pre-installed node libraries (path, fs, assert). Let me outline the process that leads to this problem: Begin by launching Visual Studio. Select File > Open Folder, then pick the root core-demo folder. In the file panel, loc ...

Alerts in Angular templates of inherited class in WebStorm

While working with WebStorm 2019.3.2, I have noticed some warnings in Angular templates: https://example.com/image.png This is happening because the properties are being initialized on the parent component instead of the child. @Component({ selector: ...

When executing prisma generate, an error of TypeError is thrown stating that the collection is

While using typescript with Prisma, I encountered an issue when trying to run prisma generate, as it kept throwing the following error: TypeError: collection is not iterable. at keyBy (/node_modules/@prisma/client/generator-build/index.js:57685:21) at ...

Determine the `overall` amount and adjust `overall` to equal `quantity * price` within a Typescript

I am looking to perform a calculation similar to this: total = quantity * price and continuously update the total when either the quantity or the price changes. template-output-snapshot app.component.html <form [formGroup]="editform" (ngSubm ...

Ensure that the dynamically inserted <title> tag remains intact in Angular even when the page is re

Can the dynamic title tag be preserved when the page is refreshed? When I refresh the page, the title tag reverts back to the original one specified in the index.html temporarily before switching back to the dynamically added one. I want the title tag to ...

Ensure that the Observable is properly declared for the item list

.html // based on the error message, the issue seems to be in the HTML code <ion-card *ngFor="let invitedEvent of invitedEvents"> <ion-card-content> <img [src]="eventPhotoUrl$[invitedEvent.id] | async"> </ion ...

Create an array with individual key-type pairs for each generic element, then iterate through the array

Consider the enum and type declarations in the code below: enum MyEnum { FIRST, SECOND }; type MyType = { firstKey: string | null, secondKey: boolean, thirdKey: MyEnum } Next, a variable is declared using the type as follows: let glob ...

Best practices for implementing "Event Sourcing" in the NestJS CQRS recipe

I've been exploring the best practices for implementing "Event Sourcing" with the NestJS CQRS recipe (https://docs.nestjs.com/recipes/cqrs). After spending time delving into the features of NestJS, I have found it to be a fantastic framework overall. ...

Verify that the Angular service has been properly initialized

I am currently testing my Angular service using Karma-Jasmine and I need to verify that the loadApp function is called after the service has been initialized. What would be the most effective approach for testing this? import { Injectable, NgZone } from ...

The NgModel within the parent component is expected to mirror the state of the child component

My Angular 10 project includes a library with a wrapper component around a primeng-component. The primeng-component utilizes ngModel. I am trying to set the ngModel in the parent-component accessing the wrapper-component, and I want any changes made to the ...

When transitioning from component to page, the HTTP request fails to execute

I have created a dashboard with a component called userInfo on the homepage. This component maps through all users and displays their information. Each user has a display button next to them, which leads to the userDisplay page where the selected user&apos ...

Finding a date from a calendar with a readonly property in Playwright

Just starting out with the playwright framework after working with Protractor before. I'm trying to figure out the correct method for selecting a date in Playwright. selector.selectDate(date) //having trouble with this ...