Why does Partial allow additional properties from a different type?

Given two interfaces, A and B, both of which have a property called x1

interface A {
  a1: number;
  a2: number;
  x1: number;  // <<<<
}

interface B{
  b1: number;
  x1: number;  // <<<<
}

We also have implementations for these interfaces named a and b

let a: A = {a1: 1, a2: 1, x1: 1};
let b: B = {b1: 1, x1: 1};

It is interesting that this assignment works, even though b1 is not part of Partial<A>:

let partialA: Partial<A> = b;

However, when we try to explicitly define the properties of Partial<A>, it fails:

let partialA: Partial<<A> = {b1: 1, x1: 1};

Can someone explain why this happens?

Answer №1

Join me on this journey as we delve into subtypes and base types in Typescript:

In Typescript, a type with more properties should be assignable to a base type where a subset of the properties is expected. This means that a source object with additional properties can be assigned to a target object expecting only a subset of those properties:

let source = { a1: 0, a2: 0}
let target: { a1: number } = source

Interestingly, due to structural typing, Partial<A> is considered a subtype of Partial<B>, and vice versa. Missing optional properties do not disqualify a type from being a subtype, as an empty object {} can serve as the base type for any other type. The compiler confirms this through conditional types:

type q1 = Partial<A> extends Partial<B> ? "Y" : "N" // Y
type q2  = Partial<B> extends Partial<A> ? "Y" : "N" // Y

There is one exception to this rule, which is excess property checks when assigning object literals directly to a specific type reference. This check prevents errors caused by unintentional extra or misspelled properties:

let target: { a1: number } = { a1: 0, a2: 0} // err  

The purpose of excess property checks is to catch common mistakes in object literal assignments. However, these checks do not apply to indirect assignments like

let partialA: Partial<A> = b;
.

Another complexity arises from the concept of weak types, such as Partial<A>. These types have only optional properties and are non-empty. Any object can be assigned to a weak type since they do not demand mandatory properties:

let k = { foo: 0 }
let partialA: Partial<A> = k;

Despite k having no common properties with Partial<A>, it remains assignable because weak types require no specific properties. The introduction of the weak type detection rule enforces constraints on assigning completely unrelated types to weak types.

In your scenario, both Partial<A> and Partial<B> share the property x1, allowing for their inter-assignability without triggering enforcement of the weak type detection rule. As long as there are common properties present, the assignment between subtypes is generally permitted.

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

There are several InputBase elements nested within a FormControl

There seems to be an issue: Material-UI: It appears that there are multiple InputBase components within a FormControl, which is not supported. This could potentially lead to infinite rendering loops. Please only use one InputBase component. I understand ...

Angular rxjs: Wait for another Observable to emit before subscribing

My setup involves having 2 subscriptions - one is related to my ActivatedRoute, and the other is from ngrx Store. ngOnInit() { this.menuItems$ = this.store.select('menuItems'); this.menuItems$.subscribe(data => { this.menuItem ...

The input argument must be of type 'PollModel', as the property 'pollId' is required and missing in the provided 'any[]' type

Hey there! An issue popped up when I tried to pass an empty array as a model in my Angular project. The error message reads: "Argument of type 'any[]' is not assignable to parameter of type 'PollModel'. Property 'pollId' is ...

How to nullify the valueChanges pipe in Angular RxJS until the observable is resolved

A challenge I am facing is piping the valueChanges from a select element to trigger the appropriate API request and displaying a spinner until the response is received. Additionally, I am trying to utilize publish() and refCount() methods so that I can use ...

Generate a customized object with specified criteria

Looking to achieve the same goal as described in this reference, I am attempting to generate an object of a mapped type. Despite my efforts, I continue encountering type errors during implementation. Here is a simplified example: [code snippet] When ass ...

What is the best method for importing CommonJS into TypeScript while maintaining forward compatibility?

In terms of future compatibility with both TypeScript and the ES module spec, which method is the most reliable for importing a CommonJS module? import * as foo from "foo import foo = require("foo") const foo = require("foo") If ...

Populate an empty value in a key-value pair by using the subsequent value

Replace an empty value in a key-value pair with the first value of the next key. myitems = { 'items1': [{first:true, second:false}, {first:true, second:true}], 'items2': [], //should be filled with {first:true, second:false} 'it ...

Is there a way to prevent QtLinguist from opening every time Visual Studio tries to display a TypeScript file?

Ever since I installed Qt tools for Visual Studio, my Ctrl+click on a class name triggers Qt Linguist: https://i.stack.imgur.com/USAH1.png This hinders me from checking type definitions, even though Visual Studio has already parsed them. The type informa ...

Creating an Express server using Webpack, TypeScript, and ESM

Hello, I am currently working on a small project using node.js and TypeScript with webpack. Here is a snippet of my tsconfig.json file: tsconfig.json { "compilerOptions": { "lib": ["ESNext"], "target": "ES2020", "module": "NodeNext", "mod ...

Are there any solutions to refresh a page by clicking a button in next.js?

I am currently learning how to work with next.js and I'm facing an issue where I need to reload my page to make a new API request. As a beginner, I'm not sure how to achieve this. I've tried a few methods but none of them seem to work. Below ...

The property 'key' is not found within the type 'string | { key: string; element: Element; }'

Why is this error message appearing? The issue states: Property 'key' does not exist on type 'string | { key: string; element: Element; }' It seems to be triggered by the following code: <th key={header?.key ? header.key : header} r ...

Exploring the Power of PrimeNG and Observables in Angular 4 with RxJS

After configuring my Angular 4 project with a service like this: const usersURL = 'http://my.super.url.php'; @Injectable() export class UserService { users: Observable<User[]> constructor (public http:Http) let tick$ = Observ ...

Struggling to make type definitions work in react-hook-form 7

Upon defining the types of my form fields, I encountered an issue where each field seems to take on all three different types. This is puzzling as I have specified 3 distinct types for my 3 different fields. What could be causing this confusion? https://i ...

A guide on iterating through a JSON object fetched using Http in Angular 2/Typescript

I am attempting to extract specific data from my JSON file using http. The structure of the JSON is as follows: [{"name":"Name1","perc":33},{"name":"Name2","perc":22},{"name":"Name3","perc":41}] To loop through this retrieved object, I use the following ...

Is there a way in TypeScript to specify that the parameters of an interface should be the keys of an object?

Here is the code I'm working with: interface IOrder { id: string created: string name: string age: number } type OrderKey = keyof IOrder const columnNames: OrderKey[] = ['id', 'name', 'age', 'created'] ...

What are the steps for integrating mongoDB with an angular2 application?

I currently have my angular2 & mongoDB setup successfully. While I've managed to read JSON files using the HTTP service, my goal is to create a fully functional application with database connectivity as well. I'm seeking advice on how to con ...

The parameter type 'DateInput' cannot be assigned to the parameter type 'Date'

I am currently utilizing fullcalendar for my project. However, I would like to utilize my local models instead of fullcalendar's model. The issue arises when attempting to create a new instance of my own model, as it displays the following error messa ...

Dealing with the error "Type 'date[]' is not assignable to type '[date?, date?]' in a React hook

I'm attempting to assign a date range but encountering an error that states: Type 'Date[]' is not assignable to type '[Date?, Date?]'. Types of property 'length' are incompatible. Type 'number' is not assignab ...

Tips for getting Atom cucumber step jump package to function properly on a Windows operating system

Just recently, I installed the Atom text editor along with the cucumber-step package available at this link. However, after pressing CTRL+ALT+j, it failed to jump to the step implementation/definition. My operating system is Windows 10 and I am utilizing ...

typescript persist zustand: typing your store

Running a simple store interface CartState { cart: { [id: string]: CartDto }; addItem: ({ id, image, name, price }: Omit<CartDto, "quantity">) => void; removeItem: (id: string) => void; reset: () => void; } export const use ...