What causes the inconsistency in TypeScript's structure typing?

It is well-known that TypeScript applies structure typing, as demonstrated in the following example:

interface Vector {
   x: number;
   y: number;
}

interface NamedVector {
   x: number;
   y: number;
   name: string;
}

function calculateLength(v: Vector) {
   return Math.sqrt(v.x * v.x + v.y * v.y);
}

const v: NamedVector = { x: 3, y: 4, name: 'zee' };
calculateLength(v);   // compiles without errors, result is 5

This allows calculateLength to be called with a NamedVector because their structures are compatible.

However, when it comes to assignment, structure typing is not used anymore:

const v: Vector = { x: 3, y: 4, name: 'Zee' };  // compile error, 'name' does not exist in type 'Vector'

Based on the definition of structure typing, { x: 3, y: 4, name: 'Zee' } should also be compatible with Vector, so why doesn't structure typing work in this case?

Furthermore, what Utility Types can be used to describe a type that must contain both x and y fields along with some other fields, in order to do something like:

const v: XXX<Vector> = { x: 3, y: 4, name: 'Zee' };

Answer №1

It's hard to imagine a practical scenario where this approach would be useful, but the most straightforward way to down-cast is simply by casting the object.

const obj = { x: 3, y: 4, name: 'John' } as Object;

However, keep in mind that you won't be able to access obj.name, making this exercise seemingly pointless.

Answer №2

In response to your second inquiry

interface Vector {
   x: number;
   y: number;
}
const v: Vector & {[x:string]: any}= { x: 3, y: 4, name: 'Zee' }; 

Play around with Typescript here

The initial question lacks sufficient detail for a clear answer, in my view.

Answer №3

It is recommended to avoid using excess properties in Object literals. Instead, consider utilizing Custom Generics to prevent the use of excess properties.

interface Vector {
   x: number;
   y: number;
}

interface NamedVector {
   x: number;
   y: number;
   name: string;
}

function calculateLength(v: Vector) {
   return Math.sqrt(v.x * v.x + v.y * v.y);
}

type Optional<T, N extends keyof T> = Partial<Pick<T, N>> & Omit<T, N>;

const v: Optional<NamedVector, "name"> = { x: 3, y: 4, name: 'Zee' };
calculateLength(v);

ref: https://www.typescriptlang.org/docs/handbook/type-compatibility.html#starting-out

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

Adding JavaScript in the code behind page of an ASP.NET application using C#

Currently, my challenge involves inserting a javascript code into the code behind page of an asp.net application using c#. While browsing through various resources, I stumbled upon some solutions provided by this website. Despite implementing them as inst ...

Is there a way to track the loading time of a page using the nextjs router?

As I navigate through a next.js page, I often notice a noticeable delay between triggering a router.push and the subsequent loading of the next page. How can I accurately measure this delay? The process of router push involves actual work before transitio ...

How about rejuvenating a Div with some PHP magic inside?

My goal is to automatically update a div every x seconds by using the following code: The div only contains a small PHP timezone code. This is the code snippet I am implementing: <script type="text/javascript" src="http://ajax.googleapis.com/ajax/ li ...

What is the reason behind the error Generic indexed type in Typescript?

Here is a scenario where I have a specific generic type: type MapToFunctions<T> = { [K in keyof T]?: (x: T[K]) => void; }; It functions correctly in this instance: type T1 = { a: string }; const fnmap1: MapToFunctions<T1> = { a: (x: st ...

The Ajax Process continues to run even after the user has navigated away from the page

Currently, I have a JavaScript function that refreshes a specific section of a Rails-generated view every 2.5 seconds using a JS request to update a basic progress bar. function refreshPage(){ $.ajax({ type:"GET", dataType:"script" }) } s ...

Stop HTML <dialog> from automatically closing using Vue

I'm working on a project where I need to use Vue to programmatically prevent an HTML dialog element from closing when the close event is triggered. Here's the code snippet I am currently using: import {ref} from 'vue'; const dialogTe ...

Creating a VSCode extension using Vue: Step-by-step guide

I'm looking to develop a VSCode extension with Vue utilizing the VSCode webview. However, when attempting to import the compiled index.html into my extension, I consistently receive a prompt to enable JavaScript. Is there a solution for integrating Vu ...

An issue occurred while attempting to execute a function in AngularJS

Currently, I am in the process of developing a cross-platform application using AngularJS, Monaca, and Onsen UI. My current challenge involves calling a function in my controller from an ng-click() event on my view. However, upon clicking the button that ...

Implement a procedure for printing a page once the columnize operation has been completed

Hello, I have run into a problem that I need help with. Currently, I am trying to print a page after the function "columnize" has finished its task. However, the print function is executing before the columnize function completes. How can I ensure that t ...

Is there a way to automatically scroll to the bottom of a div when it first

Looking to enhance my application with a chat feature that automatically scrolls to the bottom of the chat page to display the latest messages. Utilizing VueJs: <template> <div id="app"> <div class="comments" ...

No element found with the specified exportAs value of "ngForm" on the <form> tag

I am currently experimenting with a template driven form in Angular, but I encountered an error stating **There is no directive with “exportAs” set to “ngForm"** I have made sure to import FormsModule and ReactiveFormsModule in app.module.ts as well ...

Validating a single field name with various DTO types based on conditions in a NestJS application

There is a field named postData in EmailTypeDto, but it has different types based on conditions. It may be confusing to explain in words, but the code makes it clear. export class EmailTypeDto { @IsEnum(EmailType) public type: EmailType; @ValidateIf ...

Issue with Submit Event in React - Enter Key Fails to Trigger

I'm currently experimenting with a small front-end react project that's using Soundcloud's API. The project is quite basic at the moment - it takes user input and queries the API for related songs. I've encountered an issue where the en ...

Implementing sound playback within an AJAX response

Recently, I implemented a jQuery code to automatically refresh a specific div. This auto-refresh feature uses AJAX to generate notifications whenever there is a new request from a client, similar to social network notifications. I even incorporated music f ...

Determine the estimated download duration using the $http protocol

I am experiencing an issue with a function that calculates the time it takes to download a text file (3MB in size) from my server. While it works well for single requests, when I attempt to run multiple requests simultaneously, the time spent waiting for a ...

Uploading PDF files using PHP without the need for traditional input boxes

Currently, I am utilizing a JavaScript code to add annotations to a PDF document within the browser. Once I have completed adding annotations, I save the modified document on my device and then proceed to upload it using another form. However, my goal is ...

Exploring nullish coalescing with undefined values

My function is set up to make API calls: interface getEventsPropsShape { eventId?: string; accountId?: string; eventsStartAfter?: string; } const getEvents = async ({ eventId, accountId, eventsStartAfter, }: getEventsPropsSha ...

Working with arrays and data to populate tables and cross tables using a single Eloquent Model in Vue and Laravel

There are three tables in the database: species, panel, and a cross table called species_panel. The relationship between them is that one panel can contain multiple species, so a one-to-many relationship is used. Data needs to be inserted into the panel ta ...

Tips for setting a new key and value for an existing object in TypeScript

As I transition from JavaScript to TypeScript, I am currently working on creating a Discord bot using TypeScript to familiarize myself with the environment. However, I encountered an error when attempting to add new keys to an object that was previously cr ...

Can you use an ajax post to search for a boolean in MongoDB without converting on the server side?

I am facing an issue with my mongo collection that has documents containing a boolean field: { name : "Tom", active : true } { name : "Jerry", active : false } In my application's client side, there is an element that triggers an AJAX po ...