How to automatically set member fields for string literal types in Typescript

Imagine having the following classes:

class Foo {
  type: "foo"
  constructor(public id: number) {}
}

class Bar {
  type: "bar"
  constructor(public id: number) {}
}

type SomeUnion = Foo | Bar // (x : SomeUnion).type will have the type "foo" | "bar"

When you create an instance of new Foo(1), it returns { id: 1 }. However, what if you want to automatically include type: "foo" in the returned object?

An easy fix is to assign the string constant inside the constructor like so: this.type = "class_name".

But duplicating the string constant can be error-prone. Is there a way to generate a member with the same value as the string literal without explicitly typing it out twice?

Answer №1

Let's focus on analyzing the following code snippet:

class Bar {
  kind: "bar"
  constructor(public id: number) {}
}

If we set the compiler option strictNullChecks to false, then declaring kind: "bar" implicitly allows assigning values of undefined and null to the kind property. It becomes clear that initializing the field with a value other than undefined is crucial in this scenario.


Now, let's proceed with strictNullChecks enabled (set to true). In this case, only the value "bar" can be assigned to the kind property. It seems like you are expecting the compiler to deduce the following logic:

The declaration kind: "bar" specifies that the field named kind must have type "bar". Therefore, only the value "bar" should be assigned to it. Thus, I should automatically initialize it with "bar" since no other value is valid.

The issue arises with TypeScript 2.x, even when using

strictNullChecks</code, fields can initially have the value <code>undefined
despite not allowing direct assignment of undefined. To clarify: while you cannot directly assign undefined to kind, the field can start with the value undefined if left uninitialized without triggering an error. This behavior has sparked conversations within the TypeScript community as some view it as a flaw in the language design. You can refer to the related issue report.

Ultimately, the compiler does not perform the expected reasoning mentioned above. Therefore, currently, you will need to redundantly specify the string literal type and explicitly initialize your kind properties.

Answer №2

It seems like this solution could meet your requirements. Although the string literal needs to be typed out twice, having them close together may reduce the likelihood of forgetting to update both values if the class type changes.

class Cat {
  breed: "Siamese" = "Siamese"
  constructor(public id: number) {}
}

class Dog {
  breed: "Golden Retriever" = "Golden Retriever"
  constructor(public id: number) {}
}

Answer №3

If you need the type to be a string literal rather than a generic string for use in union types throughout your program, it's crucial to define a specific type for that union. Let's call it:

type MyType = "foo" | "bar";

Then, you can implement it as follows:

class Foo {
  type: MyType = "foo";
  constructor(public id: number) {}
}

class Bar {
  type: MyType = "bar";
  constructor(public id: number) {}
}

For additional organization and efficiency, consider creating a shared base class:

class Base
  type: MyType;
  protected constructor(type: MyType) {
    this.type = type;
  }
}

class Foo extends Base {
  constructor(public id: number) {
    super("foo");
  }
}

class Bar extends Base {
  constructor(public id: number) {
    super("bar");
  }
}

Answer №4

Any thoughts on this?

function Bar {
    category: string;
    constructor(public code: number) {
       this.category = "class_category";
    }
}

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

What is the process for accessing a read-only markdown preview in a vscode extension?

I'm currently working on developing a custom Visual Studio Code extension. I have implemented a feature where clicking on a button should open a markdown preview with specific content. The code snippet I am using for this functionality is as follows: ...

Convert data into a tree view in JavaScript, with two levels of nesting and the lowest level represented as an array

Here is an example of a JSON object: [ { "venueId": "10001", "items": [ { "venueId": "10001", "locationId": "14", "itemCode": "1604", "itemDescription": "Chef Instruction", "categoryCode": "28", ...

Arranging strings in descending order using Typescript

I was attempting to arrange a string[] in a descending order. This is what I have come up with so far: let values = ["Saab", "Volvo", "BMW"]; // example values.sort(); values.reverse(); Although this method is effective, I am wondering if there is a mo ...

Using TypeScript for Geolocation

Consider the code snippet below: pos:number; getPosition() { navigator.geolocation.getCurrentPosition((position) => { this.pos = position.coords.latitude; During debugging, the value of 'this.pos' is undefined, while 'posi ...

How to vertically align Material UI ListItemSecondaryAction in a ListItem

I encountered an issue with @material-ui/core while trying to create a ListItem with Action. I am looking for a way to ensure that the ListItemSecondaryAction stays on top like ListItemAvatar when the secondary text becomes longer. Is there any solution to ...

Exploring Angular Scope within a Typescript-based javascript function

My current setup involves Typescript with Angular combined with Breezejs. class CounterController { count: number = 0; static $inject = ['$scope']; constructor($scope) { $scope.vm = this; } setCount14(): void { ...

Using Type TTextKey to access TOption is not allowed

I'm struggling to understand why there is a complaint about return option[optionTextKey] with the error message: Type TTextKey cannot be used to index type TOption Here's the code snippet causing the issue: type Props< TTextKey, TOpti ...

Issue with Material UI grid not rendering properly in TypeScript environment

I've been trying to replicate a grid from material-ui using React and Typescript. You can see a live demo here. I modified the example to work with Typescript, so my demo.tsx file looks like this: Code goes here... If you check out the live demo, y ...

Resolving TypeScript Problem: Showing Error Alerts from React Hook Form

Currently, I am developing a registration form using react-hook-form within a React application. The form I'm working on includes validation for various fields, and my goal is to show error messages for each field. However, I have hit a bump in the ro ...

Translate Typescript into Javascript for use in React applications

Can anyone assist me in converting this Typescript code to Javascript? function ImageMagnifier({ src, width, height, magnifierHeight = 100, magnifieWidth = 100, zoomLevel = 1.5 }: { src: string; width?: string; height?: string; magnifie ...

Triggering the detection of changes even when the value linked to remains the same

I'm facing an issue with a component that is supposed to react to changes in input controls by reformatting the input and removing certain characters. If the removed character corresponds to the previous value, the component fails to detect any change ...

Setting a default value for a data type within Typescript

My goal is to set default values for all properties in my custom type if they are not defined. This is what I have done: // custom type with optional properties type MyType = { // an example property: str?: string } // with numerous properties, assign ...

How do I maintain the Type<any> throughout my application state in NgRx without compromising on best practices?

Utilizing Angular 11.1.2 and rxjs 6.6.2 I am working on developing an application that dynamically displays a list of components. I have successfully achieved this functionality independently. However, I am currently encountering challenges when transitio ...

Associating function parameters with object types in TypeScript

In the conclusion of this post, I provide operational code for associating object types with a function that accepts an object containing matching properties. The code snippet I shared results in 'result' being resolved as: type result = { GE ...

Issue encountered when attempting to save items in the browser's local storage

I'm encountering an issue: ERROR Error: Uncaught (in promise): DataCloneError: Failed to execute 'put' on 'IDBObjectStore': Position object could not be cloned. Error: Failed to execute 'put' on 'IDBObjectStore& ...

How to transition from using a CDN to NPM for implementing the Google Maps JavaScript MarkerClusterer?

Currently integrating Google Maps JavaScript MarkerClusterer from CDN, I am considering transitioning to the NPM version for Typescript checking in my JavaScript files. However, I am encountering difficulties understanding how to make this switch. The docu ...

Sorting by Date in JavaScript

My goal is to filter out the elements in an array that have a date (converted from string) greater than a specific date. _this.downloadData.forEach(_d => _d.LogTime = _d.LogTime.toString()); console.log(_this.downloadData.filter(x=>new Date(x.LogTi ...

I am seeking to divide an array into multiple arrays, each based on the presence of a specific element from a separate array

Is there a way to split an array into multiple arrays based on specific elements from another array? For example, take the following situation: var test = ["1","2","3","env","6","7","8","uat","2344","wersdf","sdfs"]; var test2=["env","uat"]; In this cas ...

What is the best way to conduct tests on this React component using Jest?

I'm currently working on increasing the test coverage for a wrapper component in my codebase using jest. Although I haven't been able to identify any specific usage of this component, it's important to ensure that it is covered by tests. M ...

Using Nest JS to Handle Null Responses in Services

When using Nest Js to call Axios and get data from the Facebook API, I encountered a problem where the service was returning a null value. Strangely, when I tried calling the response using console.log, it did return a value. Any suggestions on what I migh ...