Determine the data type of a class property by referencing the data type of a different property within the

Why am I getting an error when assigning to this.propertyB in TypeScript?

class Example {
    public readonly propertyA: boolean;
    private readonly propertyB: this['propertyA'] extends true ? null : 'value';

    public constructor() {
        this.propertyA = true;
        this.propertyB = this.propertyA ? null : 'value'; 
                    //^ Type '"value" | null' is not assignable to type 'this["propertyA"] extends true ? null : "value"'.
                    // Type 'null' is not assignable to type 'this["propertyA"] extends true ? null : "value"'.
    }
}

@EDIT: Attempted with a generic parameter for the class

class Example<T extends boolean> {
    public readonly propertyA: T;
    private readonly propertyB: T extends true ? null : 'value';

    public constructor(arg: T) {
        this.propertyA = arg;
        this.propertyB = this.propertyA ? null : 'value';
    }
}

Error message:

Type '"value" | null' is not assignable to type 'T extends true ? null : "value"'.
  Type 'null' is not assignable to type 'T extends true ? null : "value"'.ts(2322)

Answer №1

The concept of the polymorphic this type, introduced in the microsoft/TypeScript#4910 pull request, represents an implicit generic type parameter that is restricted to the current type. To illustrate, you can view this as similar to This in the declaration of a class like

class Example<This extends Example<This>> {⋯}

In your case, the propertyB property exists as a conditional type dependent on a generic type parameter. The TypeScript compiler cannot determine its specific value until it knows the type argument assigned to the type parameter. As a result, this property behaves like a somewhat enigmatic type. TypeScript struggles to assess what values can be assigned to it, leading to error prompts for attempts such as this.propertyA ? null : 'value'.

Though it seems logical that the evaluation of this.propertyA should influence the type of this, TypeScript fails to capture this nuance. The open issue at microsoft/TypeScript#33912 challenges the lack of support in modeling function return types and faces complexities due to assumptions needed when aligning generic conditional types with conditional checks.

Addressing these concerns proves challenging, evident from scenarios where assignments between a generic conditional type like T extends U ? V : W and its counterpart isU(t) ? v : w are not inherently compatible. This discrepancy reflects a broader problem showcased by the example provided:

class Example {
  public readonly propertyA: boolean;
  private readonly propertyB: this['propertyA'] extends true ? null : 'value';

  public constructor() {
    this.propertyA = true;
    this.propertyB = this.propertyA ? null : 'value';
  }
  propB() { return this.propertyB }
}

class Subclass extends Example {
  public readonly propertyA: false = false;
}
new Subclass().propB().toUpperCase(); // RUNTIME ERROR

In this scenario, despite refining the type of propertyA in Subclass, runtime errors arise due to inconsistencies in assigning values to propertyB. While a workaround involving type assertions to ensure safety exists, implementing complete type safety remains elusive to TypeScript analysis.

To eliminate compiler errors, a type assertion can validate the assignment's integrity:

this.propertyB = (this.propertyA ? null : 'value') as
  this['propertyA'] extends true ? null : 'value'; // no error

This resolves the compile-time issues, but necessitates meticulous verification of safety considerations before executing the assertion.

For further exploration, refer to the playground link for visualizing the discussed code snippets.

Answer №2

class Sample {
    public readonly itemOne: boolean;
    private readonly itemTwo: this['itemOne'] extends true ? null : 'example';

    public constructor() {
        this.itemOne = true;
        this.itemTwo = this.itemOne ? null! : 'example' as this['itemOne'] extends true ? null : 'example';
    }
}

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

Resize the textarea to fit a maximum of five lines, and display a scrollbar if necessary

Explanation: I am facing an issue in Angular 2 regarding the chat screen. I need the chat screen to dynamically increase in size as I type, up to a maximum of 5 lines, and then show a scrollbar. How can I achieve this functionality? Problem: The current b ...

The base class is invoking a function from its child class

There are two classes, a base class and a derived one, each with an init function. When constructing the derived class, it should: Call its base constructor which: 1.1. Calls its init function Call its own (derived) init function. The issue is that ...

Listening to events on the iterative variable of NgFor directive in Angular 2

Angular2 has been my latest exploration in solving a unique data binding challenge. In my UI, I've presented a javascript array of objects like a database recordset in an HTML table. Each row contains menus and inputs allowing users to modify the rec ...

ApolloClient encounters type mismatches with ApolloLink

Struggling with creating ApolloClient using TypeScript, encountering type-errors that I'm unable to resolve. Seeking guidance on what steps to take next. Provided below is a snippet of the code (functions fine with JavaScript) for setting up the clie ...

Execute various Office Scripts functions within a single script based on the button that is selected

Imagine you have an Excel spreadsheet with two buttons named populate-current and populate-all. Both buttons execute the same Office Script function that looks something like this: function populateByRowIndex(workbook: ExcelScript.Workbook, rowIndex: numbe ...

The useEffect hook is failing to resolve a promise

I have received a response from an API that I need to display. Here is a snippet of the sample response (relevant fields only): [ { ...other fields, "latitude": "33.5682166", "longitude": "73 ...

Creating a TypeScript type based on the static values of a class

In my Market class, there is only one parameter: name. class Market { name: string constructor(name: string) { this.name = name } } Next, I have a Markets class that contains a static collection of multiple markets. class Markets { static M1 ...

The error message related to TupleUnion in TypeScript is indicating that the depth of type instantiation may be too deep and could

Recently, I've been delving into a TypeScript utility type known as TupleUnion. This useful type came to my attention through a fascinating Twitter post, and I've observed it being utilized in various Stack Overflow solutions. Here's how the ...

The module `perf_hooks` could not be resolved

Trying to integrate perf_hooks library from the nodeJS Performance API into my React Native project has been quite a challenge. Here's the snippet of code I've been working with: import {performance} from 'perf_hooks'; export const mea ...

"Exploring the Depths of Angular with Google Maps and Karma

After upgrading an Angular project from version 8 to 11 and updating the dependencies, I encountered an issue with compatibility. The project previously used the @agm/core package, which is not compatible with Angular 11. I replaced it with @angular/google ...

In AngularJS, the use of the '+' operator is causing concatenation instead of addition

Looking for assistance with my TypeScript code where I've created a basic calculator. Everything is working as expected except for addition, which seems to be concatenating the numbers instead of adding them together. HTML CODE : <input type="tex ...

Converting a string to a number is not functioning as expected

I am facing a problem with an input shown below. The issue arises when trying to convert the budget numeric property into thousands separators (for example, 1,000). <ion-input [ngModel]="project.budget | thousandsSeparatorPipe" (ngModelChange)="projec ...

"Choose one specific type in Typescript, there are no in-b

Need help returning an object as a fetch response with either the property "data" or "mes": { data: Data } | { mes: ErrMessage } Having trouble with TypeScript complaining about this object, let's call it props: if (prop.mes) return // Property &a ...

Tips for utilizing array.items in joiful validation?

Can someone provide an example code or a link on how to correctly use the joyful validation for array items? I attempted the array.items validation code using joyful, but I am not sure how to specify the items. Thanks in advance! ...

Unpacking the information in React

My goal is to destructure coinsData so I can access the id globally and iterate through the data elsewhere. However, I am facing an issue with TypeScript on exporting CoinProvider: Type '({ children }: { children?: ReactNode; }) => void' is no ...

The 'component' property is not found in the 'IntrinsicAttributes' type in this context

I am facing an issue with a component that is not compiling properly: export default function MobileNav({routes, currentRouteIndex, handlePressedRoutedIndex}: MobileNavProp) { ... return ( <React.Fragment> ... ...

Issue with uploading video files using ng2-file-upload in Angular7 and ASP .Net Core 2.1

While working on my project, I encountered an issue with uploading video files using ng2-file-upload to the server. The photo upload functionality is working fine, but when attempting to upload a video file larger than 27MB, the process gets canceled autom ...

What is the reason for Google Chrome extension popup HTML automatically adding background.js and content.js files?

While using webpack 5 to bundle my Google Chrome extension, I encountered an issue with the output popup HTML. It seems to include references to background.js and content.js even though I did not specify these references anywhere in the configuration file. ...

I'm having trouble setting a value for an object with a generic type

I am attempting to set a value for the property of an object with generic typing passed into a function. The structure of the object is not known beforehand, and the function receives the property name dynamically as a string argument. TypeScript is genera ...

Guide on Implementing a Function Post-Rendering in Angular 2+

I'm looking to implement some changes in the Service file without modifying the Component.ts or directive file. Here's what I need: 1) I want to add an event listener after the service renders its content (which is generated by a third-party tool ...