Surprising behavior of TypeScript's Record<number, Type> type

Exploring the Record type led me to an unexpected discovery while working in Typescript 5.16.

If I define a Record<string, T> type and create this object:

const a: Record<string, T> = {
  123: someData,
  x: someData
}

This code runs without errors. The reason for this is likely because in JavaScript, number indices on objects are automatically converted to strings, so this behavior is somewhat anticipated. However, if I introduce a symbol type as a key, it does not produce any errors (symbols typically do not get coerced into other types). Even with a Record<number, T>, symbols can be used as keys alongside numeric indices. What adds to the confusion is that if I try something like

const a: Record<number, T> = {
  123: someData,
  [Symbol.for("ABCD")]: someData
}

the compilation is successful. However, using a predefined symbol like Symbol.iterator (only when the key type is number as in the previous example) results in an expected error. View here.

Is there a specific reason for this unusual behavior or have I overlooked something?

Answer №1

Excess property checking in TypeScript is not a core part of the type system but rather an additional feature. It's not essential for ensuring type safety, as it only applies in specific cases.

In TypeScript, values can have more properties than what is strictly required by their types. This concept allows interface and class hierarchies created through extension to act as hierarchical types. For example:

interface Foo { fooProp: string }
interface Bar extends Foo { barProp: string }
const bar: Bar = { fooProp: "", barProp: "" };
const foo: Foo = bar; // this works fine

While Bar may have extra properties not present in Foo, it doesn't pose a type safety risk. Excess property checks serve more as a helpful tool than a critical feature.


There are scenarios where excess property checking does not seem to occur, such as with computed properties. The behavior is categorized as a missing feature according to microsoft/TypeScript#36920.

When the compiler cannot infer a single literal type for a computed property, it gets widened to string, number, or

symbol</code, and bypasses excess property checks. For instance:</p>
<pre><code>const anotherFoo: Foo = {
  fooProp: "",
  ["bar" + "Prop"]: "" // no error despite being a computed property
}

The same principle applies to keys with symbol values. Unique symbols trigger an excess property warning, while non-unique symbols of type symbol do not.

Computed properties of non-literal types escape excess property checks. As a result, warnings will not be issued for non-literal computed keys that don't align with the expected interface structure.

For further information and code examples, please refer to the Playground link.

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

Deleting the First Item from an Array in Typescript using Angular

Clicking my Button in .html <button (click)="deleteFirst()">Delete First</button> My array setup and removal function in .ts: people = [ {first: "Tom", last: "Brown"}, {first: "Ben", last: &qu ...

Extracting and retrieving the value from the paramMap in Angular/JavaScript

How can we extract only the value from the router param map? Currently, the output is: authkey:af408c30-d212-4efe-933d-54606709fa32 I am interested in obtaining just the random "af408c30-d212-4efe-933d-54606709fa32" without the key "authke ...

Exploring the archives of PubNub within Angular5

I've been working on integrating PubNub history into my web app, but I'm currently only able to view it in the console. Here's what I have so far: pubnub.history( { channel: 'jChannel', reverse: false, ...

Angular - optimizing performance with efficient HTTP response caching tactics

I'm managing numerous services that make requests to a REST service, and I'm looking for the optimal method to cache the data obtained from the server for future use. Can someone advise on the most effective way to store response data? ...

Adding a fresh element to an array in Angular 4 using an observable

I am currently working on a page that showcases a list of locations, with the ability to click on each location and display the corresponding assets. Here is how I have structured the template: <li *ngFor="let location of locations" (click)="se ...

What steps can be taken to troubleshoot a TypeScript-powered Node.js application running in WebStorm?

Seeking advice on debugging a node.js application utilizing TypeScript within WebStorm - any tips? ...

Is it possible to enable tooltips to function through the innerHTML method?

Currently, I am utilizing the innerHTML attribute to modify the inner HTML of a tag. In this instance, it involves the <td></td> tag, but it could be applied to any tag: <td *matCellDef="let order" mat-cell [innerHTML]="order. ...

What is the best way to retrieve all WebSockets present on the current page utilizing Puppeteer in a TypeScript environment?

Is there a way to efficiently gather all WebSockets on the current page in order to easily send messages through them? I've been attempting the following: const prototype = await page.evaluateHandle("WebSocket.prototype"); var socketInst ...

What is the best way to dynamically add a new item to an object in Typescript?

var nodeRefMap = {}; function addNodeRef(key: String, item: Object){ console.log("Before:"); console.log(nodeRefMap); nodeRefMap = Object.assign({key: item}, nodeRefMap); console.log("After:"); console ...

A guide on simulating mouse events in Angular for testing Directives

I am currently exploring the functionality of a column resizable directive that relies on mouse events such as mouseup, mousemove, and mousedown. resize-column.directive.ts import { Directive, OnInit, Renderer2, Input, ElementRef, HostListener } from "@a ...

Leverage tsconfig.json within the subfolders located in the app directory during Angular build or ng-build process

In our Angular project, I am attempting to implement multiple tsconfig.json files to enable strictNullChecks in specific folders until all errors are resolved and we can turn it on globally. I have been able to achieve this functionality by using "referen ...

What steps can I take to correct my code so that it only shows a single table?

I'm facing an issue while trying to display my dynamic JSON data. It's rendering a table for each result instead of all results in the same table. My array data is coming from the backend API. const arr = [ { "Demo": [ ...

Hapi and Bell's attempt at authenticating with Twitter was unsuccessful

Currently, I have developed a basic backend API that requires multiple authentications. My current challenge is connecting to the Twitter API using Bell. However, instead of displaying the authentication page for the app, an error is being shown: {"statusC ...

Employee plus Concave Authentication

After incorporating a module that uses Convex into my Clerk authentication application, everything seemed to work smoothly. However, I encountered an issue when attempting to refresh the page after logging into the new module. Suddenly, I received an error ...

What is the appropriate data type to specify for the useLoaderData() function, and in what

I'm currently delving into the deep #6 tutorial on NetNinja's react-router, but I'm attempting to implement it using TypeScript. My task involves fetching data from a JSON object, utilizing the useLoaderData() hook, and trying to properly ma ...

Exploring the power of Javascript for number lookup

I am currently working on a coding project using TypeScript and JavaScript to locate a specific number provided by the user within a list. The goal is to display whether or not the number is present in the list when the 'search' button is pressed ...

What is the best way to anticipate a formal announcement?

Hey there! I'm trying to set options for my Datatable and add a new field in my objects, but I need to await the completion of these dtOptions. How can I achieve this in the ngOnInit lifecycle hook? export class MyDashboardComponent implements OnInit ...

Is there a way to organize items in an array alphabetically according to a predetermined key value?

I have an array of objects containing countries with various values for each country. My goal is to list them alphabetically. // globalBrands { [ { id: 1, title: 'Argentina', content: [{url: 'w ...

Executing jasmine tests in Visual Studio Code - a step by step guide

After setting up visual studio code with jasmine and typescript installed, I have created a spec file named TestSpec.ts. describe("Testing", () =>{ it("should pass", () =>{ let msg = "Welcome to TypeScript"; //I want to print the msg firs ...

"Troubleshooting the GetObject() function dysfunction following a runtime upgrade from Node.js version 6.1 to Node.js version

My current setup involves using AWS Lambda with NodeJS runtime, and I recently got a message from AWS stating that they will no longer support Lambdas running on node.js 6.10 runtime. The task at hand is to retrieve objects from S3 and create a stream fro ...