The parameter type is carried over from the constructor to the class in TypeScript

I have defined a union type for my Data Transfer Object (DTO) that includes various property types such as text, date, and number. Now, I am trying to create a class based on this DTO, but I am encountering an issue where the type of the 'value' property is showing up as unknown instead of the expected type.

export enum PropertyType {
  Text = 'text',
  Date = 'date',
  Number = 'number',
  //...
}

export interface PropertyDtoBase {
  prompt?: string;
  required?: boolean;
  // ...
};

export type PropertyDto = PropertyDtoBase & (
  { type: PropertyType.Text; value?: string; } |
  { type: PropertyType.Date; value?: Date; } |
  { type: PropertyType.Number; value?: number; } |
  // ...
);

In the generated class, I am attempting to carry over the type definition for the 'value' property from the DTO. However, it is only displaying as unknown. How can I maintain the correct type for the 'value' property in the class?

export class Property {
  prompt?: string;
  required?: boolean;
  type?: PropertyType;
  value?: Exclude<ConstructorParameters<typeof Property>[0], undefined>["value"];
  // ...

  public constructor(dto?: PropertyDto) {
    Object.assign(this, dto);
    //...
  }
};

const x = new Property({ type: PropertyType.Text, value: "test" });
if(x.type === PropertyType.Text) {
  x.value // value is unknown here, but should be string
}

If anyone has suggestions on how to preserve the correct typing for the 'value' property from the DTO within the generated class, please let me know!

Answer №1

To turn your DTO into a class, you can define it as a generic class.

class Property<T extends PropertyDto> {
  prompt?: string;
  required?: boolean;
  type?: T['type'];
  value?: T['value'];

  public constructor(dto?: T) {
    Object.assign(this, dto);
  }
}

Example of usage:

const x = new Property({ type: PropertyType.Text, value: 'test' });

// TypeScript infers that x.type is PropertyType.Text
console.log(x.value) // "test"

It's worth noting that there's no need to explicitly check if x.type is equal to PropertyType.Text to determine that x.value is of type string. TypeScript automatically recognizes it!

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

Ways to indicate in Typescript that a value, if it exists, is not undefined

Is there a way to represent the following logic in TypeScript? type LanguageName = "javascript" | "typescript" | "java" | "csharp" type LanguageToWasmMap = { [key in LanguageName]: Exclude<LanguageName, key> ...

Using Angular and TypeScript/javascript singletons across multiple browser tabs

I am curious about whether the TypeScript singleton class, used as an MVC model object in my Angular application within one browser tab, would be different from or the same as the singleton loaded into another tab within the same browser instance. The set ...

Encountering a problem: Unable to locate a supporting object '[object Object]' of type 'object' when attempting to populate a list of objects

Struggling to populate the options with server data, I tried simplifying the logic yet encountered the same error. Here's the HTML snippet for the options: <div class="col-md-4"> <mat-form-field class="example-full-width" *ngIf="!isAdmin; e ...

Testing a stateless React component with withRouter() using Enzyme and ways to pass the match parameter

I have a React functional component that I am testing and it is wrapped in withRouter from react-router-dom. The component's code structure is shown below. import * as React from 'react'; import { Switch, Route, withRouter, RouteComponentPr ...

Guide to customizing the value appearance in tooltip axispointer chart (angular)

Check out the code snippet here: https://stackblitz.com/edit/angular-ngx-echarts-zn8tzx?file=src/app/app.component.ts view image description I am looking to format and add the text "UPLOAD" and "DOWNLOAD" below the date and time. For instance: 2020-02- ...

Is it possible to create a nested object inside of an array?

Looking to accomplish the following: let listOne: any = ['item1', 'item2', 'item3']; let details: any; // Previously, I had a loop running and 'row' was the response outputting items // in the listOne array const ...

Debug errors occur when binding to computed getters in Angular 2

Currently, I am integrating Angular 2 with lodash in my project. Within my model, I have Relations and a specific getter implemented as follows: get relationsPerType() { return _(this.Relations) .groupBy(p => p.Type) .toPairs() ...

Elevate the Appearance of Material UI Elements with custom CSS Sty

I am currently facing an issue while trying to customize the styling of a Material UI component using CSS. Here is the code snippet: <IconButton className="my-class"> <Close /> </IconButton> CSS: .my-class { float: right ...

Do not include the "dist" folder when exporting sub-modules in TypeScript

I've developed a basic module called modA: modA/ - package.json - dist/ - index.js - db.js - stuff.js My goal is to use the submodules "db" and "stuff" like this: import * as db from modA/db -- how can I achieve this? My package.json has main: ...

Guide to dynamically loading mat-options with values retrieved from an API array

I seem to be facing an issue as I am unable to populate the md-option with the data retrieved from an API. It feels like there might be something missing in my code. Below is the service.ts file where I make the API call and attempt to fetch the data: get ...

Enhance your workflow with Visual Studio Code by incorporating multiple commands

Embarking on my journey to create my first VSC extension by following this tutorial. Within the "extension.ts" file resides a simple hello world command. My ambition is to introduce another command called git_open_modified_files, however, the tutorial la ...

Reduce the size of log messages in cypress

I am looking to shorten the cypress messages to a more concise string, for instance: Cypress log Transform to: -assert expected #buy-price-field to have value 17,169.00. Is there a way to achieve this? I have searched through the documentation but hav ...

The production build for Angular 9 Keyvalues pipe fails to compile

After successfully running my app on the development server with ng serve, I encountered a failure when trying to build it for production. The error message that popped up was: ERROR in src/app/leaderboard/leaderboard.component.html(9,17): Argument of typ ...

Utilizing Ionic 2 with Typescript for executing forEach operations

I am in the process of migrating my AngularJS application to Angular 2. In my AngularJS controller, I had a JSON array that I was iterating through to display data in an accordion list. Now, I need to implement the same functionality in my Angular 2 compon ...

Encountering a CORS error while attempting to initiate a Github API call on my Next App

I'm currently developing a Next.js React app with TypeScript and I am wondering if I need a server to make requests to the GitHub API. In my next.config.mjs file, as shown below, the only task my app needs is to fetch content from a file in a public r ...

The essence of ReactJS generics

In my application, I developed a custom hook to handle input. The custom hook utilizes generic types to define the return types. Below is the code snippet of my implementation: interface IUseInput<T, U> { (): [T, (e: ChangeEvent<HTMLInputElem ...

Send users to the login page if they are not authenticated

Why is my middleware crashing after redirecting to the login page? import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; // To avoid crashing, this function can be marked as `async` if using `await ...

React JS state that points to another state value

I am trying to create a component that displays a list of products along with individual list items for each product. However, I keep encountering the following error: TypeError: Cannot read property 'products' of undefined new ProductList src/c ...

When a function is transferred from a parent component to a child component's Input() property, losing context is a common issue

I have encountered an issue while passing a function from the parent component to the child component's Input() property. The problem arises when the parent's function is called within the child component, causing the this keyword to refer to th ...

What is the best way to define defaultProps for a nested object?

Within a react component, there is a nested object defined in the propTypes. This setup is functioning correctly. UserCard.propTypes = { name: PropTypes.string, customer: PropTypes.shape({ email: PropTypes.string, phoneNumber: PropTypes.string, ...