How does TypeScript allow for assignment of a record to a partial object with noticeably distinct types?

Take a look at this code snippet in TypeScript. Try it out.

const x: Record<string, string> = { foo: "bar" };
const y: { baz?: number | undefined } = x; // TypeScript doesn't complain

In the given example, one might expect TypeScript to throw an error for assigning a string to a type of number | undefined. Surprisingly, the code passes type checking without any issues. Why is that?

Answer №1

Typescript is a language with structural typing, meaning if two types have similar structures, they can be assigned to each other.

// Example 1 - No Excess property check (due to implicit narrow type Record<string, string>)

const x: Record<string, string> = { foo: "bar" };

const y: { baz?: number } = x

// Example 2 - With Excess property check

const y1: { baz?: number } = { foo: 'bar' } // Error


// Demonstrating Record<string,string> is assignable to { [k: string]: any }

type Assignable = Record<string, string> extends { [k: string]: any  } ? true: false // true

Play around with the code

In the statement x: Record<string, string>, it essentially means x: { [k: string]: string } which is a broader type than { foo: "bar" }.

When types are explicitly annotated, there are no excess property checks conducted. This allows additional properties along with the required baz prop in the assignment.

The ability to add extra props works because baz is optional and accepts undefined values, hence Typescript doesn't flag an error.

We can verify that

Record<string, string> extends { baz? :number } ? true: false
will return true

However, directly assigning an object literal of the same Record type triggers a complaint from Typescript due to the excess property check.

Object literals undergo excess property checking when assigned to variables or passed as arguments. Any properties in the literal not present in the "target type" result in an error.

Note:

Record<string, string> may not be the best choice in this case. The recommended approach is using an index signature like { [k: string]: string }

With x: Record<string, string>, x.foo might seem to be a string at compile-time but could actually be string | undefined. This discrepancy arises from how --strictNullChecks functions

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

The useRef hook in typescript seems to be malfunctioning. Everything was working perfectly fine in jsx before

After encountering some errors while trying to adapt working code for typescript, I am seeking advice. The code includes a modal window that should close when anything except the window itself is clicked. Initially functioning in jsx, TypeScript has introd ...

Tips for optimizing data loading in Angular by pre-loading data to prevent unnecessary Firebase reads

Issue: One specific part of my web application is responsible for fetching a large amount of data from Firebase Firestore whenever a user visits that section. This results in hundreds of thousands of unnecessary reads to my Firestore database. Inquiry: Ho ...

How can we create a versatile Action type in typescript that can accommodate varying numbers of arguments and argument types?

When working with Typescript, encountering a duplicate type error can be frustrating. For instance, consider the following code snippet: export type Action<T> = (arg:T) => void export type Action<T1,T2> = (arg1:T1, arg2:T2) => void How c ...

How can the outcome of the useQuery be integrated with the defaultValues in the useForm function?

Hey there amazing developers! I need some help with a query. When using useQuery, the imported values can be undefined which makes it tricky to apply them as defaultValues. Does anyone have a good solution for this? Maybe something like this would work. ...

Transferring information between pages within Next.js 13

I am currently working on a form that is meant to generate a Card using the information inputted into the form, which will then be displayed. While I have successfully implemented the printing feature, I am having difficulty transferring the form data to t ...

Conceal a designated column within a material angular data table based on the condition of a variable

In the morning, I have a question about working with data tables and API consumption. I need to hide a specific column in the table based on a variable value obtained during authentication. Can you suggest a method to achieve this? Here is a snippet of my ...

Reactivate stripe subscription based on the payment date instead of the original renewal date

In my Typescript application, I have integrated Stripe subscriptions. Let's consider a scenario where a customer is on the monthly plan for $10 with auto-renewal set up. Now, if this customer has an expired card on file and misses payment on the auto- ...

The database did not respond, causing the API to resolve without sending a response for the specified endpoint (/api/dates). This could potentially lead to requests becoming stalled in Next

I have been attempting to retrieve a list of dates from my database in a straightforward manner, but unfortunately, I am not receiving any response (even after trying to log the response data to the console). The only feedback I seem to be getting when sel ...

Issue with the scoring algorithm using Angular and Spring Boot

Hello, I have created a scoring algorithm to calculate scores, but I encountered an error in "salaireNet". ERROR TypeError: Cannot read properties of null (reading 'salaireNet') at ScoringComponent.calculateScore (scoring.component.ts:33:55) ...

Tips for enlarging the font size of a number as the number increases

Utilizing the react-countup library to animate counting up to a specific value. When a user clicks a button, the generated value is 9.57, and through react-counter, it visually increments from 1.00 to 9.57 over time. Here's the code snippet: const { ...

Unable to access / while trying to open the project

I have encountered a strange bug - Whenever I close and reopen my project in Webstorm IDE and then launch the project, I receive a "cannot get" error. This issue is resolved if I delete the route {path: '', component: AppComponent}, and then the ...

Tips for handling delayed HTTP API responses in Angular

While working on my project, I encountered a delay in response when using the this.ServiceHandler.getTxnInfo([], params) API. To handle this, I implemented the use of setTimeout along with async/await. Despite these modifications, my promise ended up being ...

Issues with implementing PrimeNG Data List component in Angular 4

I'm encountering an issue with my data list in primeng as I try to run the app: Can't bind to 'value' since it isn't a known property of 'p-dataList' The HTML file looks like this: <p-dataList [value]="cars"> ...

In this tutorial, we will explore the process of extracting nested array values from JSON data and displaying it within a listview template using

In the JSON structure below, if you look at the marks array, I need to extract and display the body value of the marks array: first, second, and third. The values first, second, and third are located inside the marks Array. I am unsure how to retrieve th ...

What is the best way to implement an Angular Guard that utilizes an API service for validation and redirects in case of failure?

Hello there! I am currently working on an Angular 7 application that deals with time cards. One of the main features I have implemented is a CanActivate Guard for controlling access to certain components. The CanActivate code utilizes Observables to decid ...

Can we establish the set values for a function's parameter in advance?

I need to define the available values for a function's parameter in this way: let valueList = [ 'val1', 'val2', 'val3', ]; let getSomething = (parameter: valueList) => { // do something } I want the con ...

How can we import the entire Jasmine library using CucumberJS?

I am currently trying to implement unit testing using Jasmine and CucumberJS in my Angular v9 application. I have followed the tutorial provided by cucumber.io to set up cucumber as the default runner. However, I am facing difficulties in using Jasmine met ...

Tips for implementing absolute paths and baseUrl in TypeScript compiler

When I bundle a package using tsc, I am getting incorrect output. Here is the structure of my project directory: common └── index.ts types ├── action.ts ├── index.ts └── request.ts utils ├── event.ts ├── index.ts ├─ ...

What causes TypeScript to generate an error when using two array of object types, but not when using the shape of both?

There are two basic types of data available: type DataA = { percent: string; exchange: string; }; type DataB = { price: number; exchange: string; }; I'm puzzled as to why TypeScript gives errors when I try to use both types together: const ...

Press the 'display additional' option within ngFor in Angular 2

I have a long list of more than 50 items that I need to display. What I want to do is show only the first 10 items initially, and then when a button is clicked, reveal the next 10 items, and keep repeating this process until all items are shown. <ul ...