Utilizing generic type and union types effectively in TypeScript

When initializing my class, I often pass in either a value or an object containing information about the value. For instance:

new Field<string>('test')
new Field<string>({value: 'test', inactive: 'preview'})

However, I encounter an error with state.value: "Property 'value' does not exist on type 'FieldState'. Property 'value' does not exist on type 'T'.ts(2339)"

interface BoxedValue<T> {
  value: T 
  inactive: 'disabled'| 'preview'| 'hidden'
}

type FieldState<T> = BoxedValue<T> | T

class Field<T> {
  value: T
  _pendingValue: T

  constructor(state: FieldState<T>) {
    if(typeof state === 'object') {
      this.value = this._pendingValue = state.value
    } else {
      this.value = this._pendingValue = state
    }
  }
}

I appreciate your solution in adjusting the code, but now I have encountered a new issue.

class Field<T> {
  value: T
  _pendingValue: T

  constructor(state: FieldState<T>) {
    if(this._isBoxedValue(state)) {
      this.value = this._pendingValue = state.value // Property 'value' does not exist on type 'FieldState<T>'.Property 'value' does not exist on type 'T'.
    } else {
      this.value = this._pendingValue = state
    }
  }
  _isBoxedValue(state: FieldState<T>): boolean{
    return typeof state === 'object' && state !== null &&
      Object.keys(state).length === 2 && 'value' in state && 'inactive' in state;
  }
}

I wonder why putting the conditional check in the _isBoxedValue function instead of the constructor led to errors. Can you help me understand?

Answer №1

To ensure that your 'state' object has a 'value' property, it is recommended to use the in operator instead of relying solely on typeof state === 'object'. While the latter can confirm that 'state' is an object type (including when its value is null), it cannot guarantee the presence of the 'value' property.

The 'in' operator also serves as a narrowing expression for types.

interface BoxedValue<T> {
  value: T 
  inactive: 'disabled'| 'preview'| 'hidden'
}

type FieldState<T> = BoxedValue<T> | T

class Field<T> {
  value: T
  _pendingValue: T

  constructor(state: FieldState<T>) {
    if ('value' in state) {
      this.value = this._pendingValue = state.value;
    } else {
      this.value = this._pendingValue = state;
    }
  }
}

Updated:

For better type checking, consider using User-Defined Type Guards with the _isBoxedValue method. The type predicate state is BoxedValue<T> should be returned instead of a boolean value.

Example implementation:

interface BoxedValue<T> {
  value: T 
  inactive: 'disabled'| 'preview'| 'hidden'
}

type FieldState<T> = BoxedValue<T> | T

class Field<T> {
  value: T
  _pendingValue: T

  constructor(state: FieldState<T>) {
    if (this._isBoxedValue(state)) {
      this.value = this._pendingValue = state.value;
    } else {
      this.value = this._pendingValue = state;
    }
  }

  _isBoxedValue(state: FieldState<T>): state is BoxedValue<T>{
    return typeof state === 'object' && state !== null &&
      Object.keys(state).length === 2 && 'value' in state && 'inactive' in state;
  }
}

Answer №2

Issue

Greetings, the dilemma at hand is a common one that affects many individuals. The statement

typeof state === "object"
checks for BoxedValue, however, there seems to be a slight error: T may also represent an object.

Resolution 1

  • include an additional condition
interface BoxedValue<T> {
    value: T;
    inactive: 'disabled' | 'preview' | 'hidden';
}

type FieldState<T> = BoxedValue<T> | T;

class Field<T> {
    value: T;
    _pendingValue: T;

    constructor(state: FieldState<T>) {
        if (typeof state === 'object' && "value" in state) {
            this.value = this._pendingValue = state.value;
        } else {
            this.value = this._pendingValue = state;
        }
    }
}

Resolution 2

  • specify the data type of T
interface BoxedValue<T> {
    value: T;
    inactive: 'disabled' | 'preview' | 'hidden';
}

type FieldState<T> = BoxedValue<T> | T;

class Field<T extends (string | number /* or your type */)> {
    value: T;
    _pendingValue: T;

    constructor(state: FieldState<T>) {
        if (typeof state === 'object') {
            this.value = this._pendingValue = state.value;
        } else {
            this.value = this._pendingValue = state;
        }
    }
}

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

Sort by label using the pipe operator in RxJS with Angular

I have a situation where I am using an observable in my HTML code with the async pipe. I want to sort the observable by the 'label' property, but I'm not sure how to correctly implement this sorting logic within the pipe. The labels can be e ...

Exploring the process of importing and exporting modules in TypeScript with the help of systemjs

Is there a way to export a module using systemjs in TypeScript? I encountered the error: TS1148 cannot compile modules unless the '--module' flag is provided. Here's my code; animal.ts export class Animal { color: string; age: numb ...

The function of TypeScript map is not working properly

Encountering the error message "data.map is not a function" while trying to map data from a REST API request returning JSON data. It appears that the issue may stem from the data structure, as it seems like the returned data should be accessed with data.da ...

Issue with binding nested ViewModels/components in Knockoutjs using TypeScript does not resolve

Struggling with implementing a viewModel within another viewModel in knockout. Any assistance would be greatly appreciated. Using typescript and aiming to have a list of address controls, each with their individual viewmodel. Initially, the project functi ...

Passing variable values in Angular 6

Is there a way to transfer the value of a variable from Component1 to a variable in Component2 without using any template binding? I have two components, Header and Footer. In the Header component, there is a boolean variable called test that I need to pa ...

Strange Typescript Issue: Dependency Imports Not Recognized as Top-Level Module

Attempting to move a custom token from one account to another by following this detailed tutorial. Facing an issue with four errors showing up for all imports from the @solana/spl-token package. Tried removing the node-modules folder and reinstalling npm ...

Passing an array of items as a property to a child component in React with Typescript is not possible

In my project, I have multiple classes designed with create-react-app. I am trying to send an array of objects to child components as illustrated below. Items.tsx import * as React from 'react'; import ItemTable from './ItemTable'; imp ...

Unexpectedly, optimization causing issues on Angular site without explanation

Currently, I am utilizing Angular to construct a front-end website that searches for and showcases information obtained through API requests. Whenever I compile the project into a file bundle for static deployment using ng build, I notice that the resultin ...

How to declare and initialize a variable in Angular 2 using TypeScript

I'm currently working with angular 2 and I'm having trouble understanding how to set a variable. The variable _isLoading is being set in "this.observable.filter((event)" but it doesn't seem to change in the template. This is my TypeScript co ...

Error: The OOP class value for translateX in the Web Animation API is returning as undefined

I'm currently working on a basic animation project using JavaScript. I have utilized the Animation class from the Web Animation API. My goal is to create multiple instances of this class in order to animate different elements with varying values and r ...

Execute the function right away and then at regular intervals of X seconds

Need help with Angular 7 function call timing checkData(): Observable<string> { return this.http.get('') .pipe( map(res => { let result; result = { packageNumbe ...

Implement conditional props for a React component by linking them to existing props

In my current project, I am working on a component that has a loading state. The component has an isLoading prop which determines whether the component is currently in a loading state or not: interface CustomImageComponentProps { isLoading: boolean ...

What methods can I use to make sure the right side of my React form is properly aligned for a polished appearance?

Trying to create a React component with multiple input field tables, the challenge is aligning the right side of the table correctly. The issue lies in inconsistent alignment of content within the cells leading to disruption in overall layout. Experimente ...

Utilizing a conditional ngIf statement in HTML or incorporating a variable within typescript for logical operations

When working with our application, we often need to display or hide a button based on specific logic. Where do you think it is best to define this logic and why? In HTML: *ngIf='logic goes here' //Or *ngIf='someBoolean' and in Type ...

The correct way to add to a string array that has been passed as props to a functional component

There is a parent component that establishes a useState hook with a string array. Then, there is a child component tasked with updating the string array. To accomplish this, both the string array and the useState function are passed to the child component. ...

Unable to import necessary modules within my React TypeScript project

I am currently building a React/Express application with TypeScript. While I'm not very familiar with it, I've decided to use it to expand my knowledge. However, I've encountered an issue when trying to import one component into another comp ...

Are there any restrictions on the amount of data that can be included in a Sankey diagram created from an Excel sheet? I would

[please provide a description of the image][1]I am encountering an issue with data limitation in plotting a Sankey diagram from an Excel sheet. I have imported an Excel sheet with 1300 rows of data, but I am only able to plot 12 rows of data. Can anyone pl ...

What are the steps to troubleshoot server-side TypeScript code in NextJS with WebStorm?

I am struggling to debug the NextJS API in WebStorm while using TypeScript and navigating through the app route. It is proving to be quite challenging to efficiently debug the API without relying heavily on console.log(). ...

Encountering an error when attempting to store a value in an array of custom types: "Unable to assign properties to undefined (setting 'id')"

My model looks like this: export class SelectedApplicationFeatures { id: number; } In my TypeScript file, I imported the model as shown below: import { SelectedApplicationFeatures } from "src/app/models/selectedApplicationFeatures.model"; selec ...

I built a custom Angular application integrated with Firebase, and I'm looking for a way to allow every user to have their individual table for managing tasks

I am looking to enhance my code so that each user who is logged in has their own tasks table, which they can update and delete. Additionally, I need guidance on how to hide menu items tasks, add-tasks, logout for users who are not logged in, and display th ...