Unexpectedly in Typescript, Enum types are automatically inferred instead of being explicitly typed

Take a look at this example:

enum ItemType {
  One = 'One',
  Two = 'Two',
  Three = 'Three'
}

interface CommonProps {
  cProp1?: string,
  cProp2?: number;
}

interface OneProps extends CommonProps {
  type: ItemType.One,
  prop1: string;
}

interface TwoProps extends CommonProps {
  type: ItemType.Two;
  prop2: number;
}

interface ThreeProps extends CommonProps {
  type: ItemType.Three,
  prop3: string;
}

type ItemProps = OneProps | TwoProps | ThreeProps;

The code above establishes an enum for ItemType and also specifies the expected properties for each type of item object.

If I attempt to define some objects like this:

//----------------------------------------------------------------------

// This does not work, errors appear when creating an array
const obj1  = {
  type: ItemType.One,
  prop1: 'some value',
}

const obj2 = {
  type: ItemType.Two,
  prop2: 12
}

const obj3 = {
  type: ItemType.Three,
  prop3: 'some value'
}

const arr: Array<ItemProps> = [ obj1, obj2, obj3 ];

By hovering over obj1 in the typescript playground, you'll notice that obj1.type is typed as ItemType (and not the specific type ItemType.One), which causes TypeScript to raise an error when attempting to create an Array.

However, if I explicitly specify types like this:

//----------------------------------------------------------------------

// This works as intended
const obj4: OneProps  = {
  type: ItemType.One,
  prop1: 'some value',
}

const obj5: TwoProps = {
  type: ItemType.Two,
  prop2: 12
}

const obj6: ThreeProps = {
  type: ItemType.Three,
  prop3: 'some value'
}

const arr2: Array<ItemProps> = [ obj4, obj5, obj6 ];
//-----------------------------------------------------------------------

TypeScript doesn't raise any issues with this approach.

It seems that TypeScript widens the types by default when inferring, but further clarification on this behavior would be greatly appreciated.

Answer №1

This occurs due to

const obj1  = {
  type: ItemType.One,
  prop1: 'some value',
}

being interpreted as

{
    type: ItemType;
    prop1: string;
}

However, this type is not compatible with ItemProps. To resolve this, you can utilize the satisfies operator:

const obj1  = {
  type: ItemType.One,
  prop1: 'some value',
} satisfies ItemProps

const arr: Array<ItemProps> = [obj1]; // works fine

Alternatively, you can use the as const assertion:

const obj1  = {
  type: ItemType.One,
  prop1: 'some value',
} as const

const arr: Array<ItemProps> = [obj1]; // works fine

OR, you have the option to use literals:


const arr: Array<ItemProps> = [{
  type: ItemType.One,
  prop1: 'some value',
}]; // works fine

This showcases how TypeScript handles type inference.

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

Typescript throwing an error stating "Error parsing: Enum member names must not begin with lowercase letters 'a' through 'z'"

Within my typescript project, I am utilizing the following enum type: export enum ModelAttributeTypes { binary = 'binary', binarySet = 'binarySet', bool = 'bool', list = 'list', map = 'map', num ...

Using Generic Types in Response DTO with Typescript, NestJs, and Class Transformer

In my project, I am dealing with multiple endpoints that provide responses along with pagination details. My goal is to have a single parent type for the pagination and be able to use different data types for the data parameter. I attempted the following ...

Encountered a syntax issue within the library code while integrating Material Design with Rails, Webpacker, Typescript, and Angular

I am facing a syntax error in my Rails application, specifically in a large JS file that seems to be generated by webpacker. The error appears to be related to Angular/Material code. Interestingly, when I exclude material design, the error disappears. Here ...

Dealing with .env.local in a next.js TypeScript file: best practices

import GithubProvider from "next-auth/providers/github" import GoogleProvider from "next-auth/providers/google" const GITHUB_ID: string = process.env.GITHUB_ID as string; const GITHUB_SECRET: string = process.env.GITHUB_SECRET as strin ...

Are you looking to discontinue receiving updates from the @Output EventEmitter?

Explore the Angular website where you can find a demonstration of communication between Parent and Child components through @Output() onVoted = new EventEmitter<boolean>();. Check it out below. In this specific scenario, is it necessary to unsubscri ...

Does the Angular2.0 router only function with components, not modules?

Currently in the process of adjusting an existing angular application to integrate with the format of this Starter Project. Within my app module, there exists a submodule (tutorial) structured as follows: https://i.sstatic.net/Q9Dku.png Upon initially acc ...

The unique Angular type cannot be assigned to the NgIterable type

As a newcomer to Angular, I was introduced to types and interfaces today. Excited to apply my new knowledge, I decided to enhance my code by utilizing a custom interface instead of a direct type declaration: @Input() imageWidgets: ImageWidget; Here is the ...

Leveraging ts-loader alongside strip-loader in Webpack

I am currently facing an issue with strip-loader in my Typescript project that is built with Webpack. The ts-loader statement in my project is as follows: { test: /\.ts$/, loader: 'babel-loader?presets[]=es2015!ts-loader' } Everything see ...

Can you use getters and setters in a TypeScript declaration file?

I am facing an issue with a declaration file for the openUi framework. The framework utilizes a get<propname>() and set<propname>(var) syntax for its properties. In traditional JavaScript, the setup would look like this: sap.ui.getCore().atta ...

Is it possible in Cypress to invoke the .click() function on an Element without triggering any errors?

I am currently in the process of developing Cypress E2E tests for my Angular application. One specific page in the app features a table with a link in the third column that is identified by the class name 'link ng-star-inserted'. My goal is to h ...

Exploring the power of developing AngularJS applications using Typescript and the app

I am currently working on a basic application that utilizes Typescript and AngularJS. In my app, I have used app.js to register my controller and some route parameters: /// <reference path="../scripts/typings/angularjs/angular.d.ts" /> /// <refer ...

Exploring the parent-child relationship of three components within Angular 2

Currently, I am developing a shopping cart using Angular 2. The application consists of two components - one for categories and another for product listings, both included in the main app component as children. However, I'm facing an issue where these ...

Versatile typing capabilities

Is it possible to have a function that takes a configuration object as its parameter, specifying which properties in a data object should be read? The configuration object has two properties that correspond to keys in the data object. The configuration ob ...

The canActivate function must be responsive to the true or false value of this.authService.isLoggedIn before proceeding

I am facing a problem with my app's routing functionality. When the user logs in with their Google email, I want the app to route to the home page: "". Everything seems to work fine except for the canActivate routeGuard. During the AuthLogin ...

How can I dynamically insert a variable string into a link tag using React and TypeScript?

I am just starting out with javascript and typescript, and I need to generate a link based on certain variables. I am currently facing an issue trying to insert that link into <a href="Some Link"> Some Text </a> Both the "Some Text" and "Som ...

Utilizing the real module instead of resorting to mock usage

I've configured Jest as follows: jest: { configure: { testEnvironment: 'jsdom', preset: 'ts-jest', transform: {...}, moduleNameMapper: { antd: '<rootDir>/__mocks__/antd/index.tsx&apo ...

How can I incorporate percentage values into input text in Angular?

How can I include a percent sign in an input field using Angular, without relying on jQuery? I am looking for a solution that is identical to what I would achieve with jQuery. Here is the current status of my project: ...

Utilizing TypeScript with dc.js for enhanced data visualization capabilities

I've encountered an issue with types while working with dc.js version 4.2.7. To address this, I went ahead and installed what I believe to be the standard types module for dc.js using the following command: Command I used for Installation npm i @type ...

Encountering the error message "Received 1 argument, when expecting 4" while attempting to utilize a vuex getter in TypeScript

I encountered an issue while unit testing a getter function. The error message Expected 4 arguments, but got 1. appeared when I attempted to use the getter. My application was built using Quasar and utilizes TypeScript. The value of HttpMocks.mockToken is ...

Invoke the function when the user inputs text into the textbox

<textarea name="" id="" #text cols="30" (keydown)="WordCounter()" (change)="WordCounter()" rows="8" [(ngModel)]="user_text" placeholder="Type something here"></textare ...