How is it possible for me to assign a literal containing unknown properties to a variable of type {}?

Upon running the code below, it fails type checking with an error message stating:

Object literal may only specify known properties

type A = {a: number}
const a:A  = {a:42, b: 43};

However, when the following code is executed, it succeeds:

type A = {}
const a:A  = {a:42, b: 43};

What is the reasoning behind this behavior? Which type specifically allows objects to have an empty value {} only? It is evident that the type {} has broader acceptance.

Answer №1

TypeScript's type system operates on a structural basis, allowing for structural subtyping. This means that object types are considered open and do not restrict additional unknown properties. They are not sealed or exact as discussed in microsoft/TypeScript#12936:

type A = { a: number }
const a2 = { a: 42, b: 43 };
const a3: A = a2; // no error

This feature supports extensions of interfaces and classes. Without it, forming type hierarchies like

interface X extends Y { extraProp: any }
or
class X extends Y { extraProp: any }
would be challenging to comprehend.


However, there are scenarios where the compiler might issue warnings regarding unexpected additional properties. The excess property checking introduced in microsoft/TypeScript#3823 triggers when an object literal is directly assigned to a non-empty target. When dealing with non-empty types like {a: number}, assigning the object literal {a: 42, b: 43} to a results in a warning. Conversely, if the type is empty such as {}, no warning is produced.

Prior to the implementation of the unknown type, the usage of the empty object type {} was widespread to denote "any non-nullish type whatsoever," prompting complaints from the compiler in such cases would lead to excessive warnings.

The excess property checking mechanism should be viewed more as a linter rule than a feature of the type system.

That sums up why this behavior occurs.


In response to your query about a type that only accepts objects with value {}, the type system does not inherently prevent extra properties. There are complex workarounds like the one proposed in microsoft/TypeScript#12936 utilizing generics to constrain excess properties to the never type but these can become convoluted.

In the case of {}, an index signature with the value type never can be employed to prohibit all properties:

type A = { [k: string]: never };
const a: A = { a: 42, b: 43 }; // error
const a2: A = { a: 42 }; // error
const a3: A = {}; // okay

The practical use case for such a type may not be readily apparent, and implementing it could pose challenges.

Playground link to code

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

Unable to bring in CSS module in a .tsx file

I am currently working on a basic React application with TypeScript, but I am encountering difficulty when trying to import a CSS file into my index.tsx file. I have successfully imported the index.css file using this method: import './index.css&apo ...

A function that takes in a type identifier and a portion of a type, and then outputs the full type

I'm currently facing a challenge with TypeScript generics. I have several types (referred to as Animals) that each have a unique attribute, "type." Additionally, I have a function called createAnimal which takes the type of animal and a partial object ...

Working with multiple tsconfig.json files in Visual Studio Code for a TypeScript project

Initially, I acknowledge that there are numerous similar questions out there, but none of them seem to provide a solution to my specific issue... Here's the setup of my ElectronJS project created with Nextron and its file structure looks something li ...

Having trouble with Vue 3's `yarn serve` getting stuck at 42% while trying to import

Issue with Vue 3's yarn serve: It gets stuck at 42% when trying to import an external js file into main.ts. The problem lies in the following code: Main.ts import '@/assets/js/jquery.min.js'; No error is displayed, it just hangs at: 42% ...

We were caught off guard by the TypeScript error: an unexpected token showed up when we were expecting a constructor,

Trying to implement a function within a class in TypeScript. class Test { function add(x: number, y: number): number { return x + y; } } Encountering an error message stating: TypeScript Unexpected token, A constructor, method, access ...

Incorporating optional fields into the form builder without being mandatory

For my current project on Ionic 4, I have implemented a form builder to create and validate forms. I have also included the [disabled] attribute in the form to disable it if all fields are not valid. However, I noticed that even if I do not add Validators ...

Utilizing onCompleted appropriately for GraphQL mutations

My objective is to execute the query first, followed by a mutation that requires an id returned from the query. However, there seems to be an issue with the sequence in which both actions are triggered within the handleSubmit() function. Despite a successf ...

What could be causing TypeScript to identify my immer draft as undefined?

I'm completely lost, can someone please help me with this issue: Currently, I am trying to update a typed configuration. Within my Provider component: const [data, setData] = useImmer<typeof INITIAL_CONFIG>(INITIAL_CONFIG) ... function updateF ...

Struggling to render the template inside a .vue file in a Vue.js + TypeScript project?

Is anyone familiar with setting up a Vue TS based project? I have encountered an issue where the template data is not being rendered in the browser's DOM. The project structure can be found in this repository: https://github.com/AndrewBogdanovTSS/typ ...

How does the call method on array.prototype.includes work with arguments x and y?

Curious about the functionality of array.prototype.includes.call(x, y);. Discovered that includes() confirms if an array has the specified value and provides a true or false result. Learned that call() invokes this alongside any optional arguments. The ...

Transform React class components into function components

In my code, there is an abstract class: export default abstract class TableAction<T = any, R = any> extends React.Component<T, R> { protected abstract onClick(e: React.MouseEvent<HTMLButtonElement>): void | Promise<void>; pr ...

Efficiently load image gallery with lazy loading

Receiving an object from a service that contains an image and detailed information has me wondering about the best way to implement lazy loading for a gallery. I would like to load the images slowly as the user scrolls, rather than all at once. If anyone ...

Adding conditional props to a style object in @emotion/react with Typescript is as simple as utilizing a ternary operator

https://i.sstatic.net/KWrCP.png Can someone help me understand how to use props to control my CSS in emotion? ...

The component is not responding to list scrolling

Issue with Scroll Functionality in Generic List Component On the main page: <ion-header> <app-generic-menu [leftMenu]="'left-menu'" [rightMenu]="'client-menu'" [isSelectionMode]="isSelectio ...

Double-executing methods in a component

I have encountered an issue while trying to filter existing Worklog objects and summarize the time spent on each one in my PeriodViewTable component. The problem I am facing involves duplicate method calls. To address this, I attempted to reset the value ...

When converting a PDF to a PNG, the precious data often disappears in the process

I am currently facing a problem with the conversion of PDF to PNG images for my application. I am utilizing the pdfjs-dist library and NodeCanvasFactory functionality, but encountering data loss post-conversion. class NodeCanvasFactory { create(w, h) { ...

Steps for handling rxjs Subject completion during webpage reload/refresh

I have developed a JavaScript library that provides a class with an RxJS Subject. The class can be initialized and the Subject is accessible. export class A { private aSubject; constructor() { this.aSubject = new Subject(); } public di ...

In Angular 16, instead of receiving the actual error message, I am faced with an unexpected error response "Http failure response for http://localhost:8080/api/tutorials: 0 Unknown Error"

Currently, I am utilizing Angular 16 HttpClient to make requests to external services using a standard configuration: import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/htt ...

What is the purpose of adding a missing import in VSCode and why does it open a new tab with

Hey there! I've been experiencing an issue with my IDE VSCode for the past couple of weeks. Previously, everything was working fine but now I'm facing a peculiar problem. Whenever I miss an import in VSCode while working on my Angular project, i ...

Error: The AppModule is missing a provider for the Function in the RouterModule, causing a NullInjectorError

https://i.stack.imgur.com/uKKKp.png Lately, I delved into the world of Angular and encountered a perplexing issue in my initial project. The problem arises when I attempt to run the application using ng serve.https://i.stack.imgur.com/H0hEL.png ...