Creating a type definition for an object literal constant with intricate property types

I am looking to create a constant object literal in TypeScript with a long list of properties all having the same type. Here is an example definition with only three properties:

type ContainerSize = {
  height: string;
  width: string;
  threshold?: number;
};

const CONTAINER_SIZES = {
  '/': { height: '65px', width: '220px' },
  '/info': { height: '220px', width: '220px' },
  default: { height: '700px', width: '500px', threshold: 480 },
} as const;

The downside of the current setup is that the property types are not explicitly defined as ContainerSize. One way to fix this is by using

Record<string, ContainerSize>
as the object type:

const CONTAINER_SIZES: Record<string, ContainerSize> = {
  '/': { height: '65px', width: '220px' },
  '/info': { height: '220px', width: '220px' },
  default: { height: '700px', width: '500px', threshold: 480 },
} as const;

However, this approach allows any string as a valid key, leading to situations where accessing non-existing keys like CONTAINER_SIZES['not-existing'] won't throw an error.

Is there a better way to define the object literal without duplicating the properties, similar to the example below?

const CONTAINER_SIZES: Record<'/' | '/info' | 'default', ContainerSize> = {
  '/': { height: '65px', width: '220px' },
  '/info': { height: '220px', width: '220px' },
  default: { height: '700px', width: '500px', threshold: 480 },
} as const;

Answer №1

Consider these two options:

  1. Derive the keys by declaring the object separately first

  2. Use a dummy function that simply returns ContainerSize

Key inference from previous object

Although it should ideally be achievable in one step, here's how you can accomplish it using two steps:

const _sizes = {
    '/': { height: '65px', width: '220px' },
    '/info': { height: '220px', width: '220px' },
    default: { height: '700px', width: '500px', threshold: 480 },
} as const;
const CONTAINER_SIZES: Record<keyof typeof _sizes, ContainerSize> = _sizes;

Playground link

As you correctly pointed out (thank you!), this approach loses the read-only aspect of the property values (both for CONTAINER_SIZE's properties and the values of the ContainerSize objects), which can be rectified with Readonly in two instances:

const CONTAINER_SIZES: Readonly<Record<keyof typeof _sizes, Readonly<ContainerSize>>> = _sizes;

Playground link

A null function option

An alternative method I have utilized when enforcing ContainerSize is needed while inputting the values is to implement a do-nothing function:

const cs = (size: ContainerSize) => size;

Subsequently:

const CONTAINER_SIZES = {
    '/':      cs({ height: '65px', width: '220px' }),
    '/info':  cs({ height: '220px', width: '220px' }),
    default:  cs({ height: '700px', width: '500px', threshold: 480 }),
};

This allows for autocompletion of property names within the object literals passed into cs. (In one project where I employed this technique, I realized the need to incorporate cross-property verification logic into the function, thus it no longer remained entirely redundant...)

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

After a loop, a TypeScript promise will be returned

I am facing a challenge in returning after all calls to an external service are completed. My current code processes through the for loop too quickly and returns prematurely. Using 'promise.all' is not an option here since I require values obtain ...

Discover a method to deselect a checkbox within a separate component in angular15

I am currently dealing with Angular15 and I find myself stuck on an issue related to checkbox selection change. Situation: As per the requirements, I have a menu bar and a Checkbox. The Checkbox is generated from a reusable component which is used in the ...

Obtain a value that is not defined

Good day, I am encountering an issue with my data not accepting an undefined value. Below is the code snippet: interface IModalContatos { dados: IContatos; onSave(dados: IContatos): void; onClose(): void; } When passing this data to my modal, I rece ...

Exploring Recursive Types in TypeScript

I'm looking to define a type that can hold either a string or an object containing a string or another object... To achieve this, I came up with the following type definition: type TranslationObject = { [key: string]: string | TranslationObject }; H ...

I'm looking to locate the API documentation for AngularJS TypeScript

After transitioning from using AngularJS 1.4 and plain JavaScript to now working with AngularJS 1.5 but utilizing TypeScript, I have found it challenging to find helpful documentation. For instance, when trying to inject services like $q or $timeout into m ...

Different ways to handle dialogs in React with TypeScript

I'm currently working on developing a modal component in React TypeScript and I'm facing some issues in determining the correct type for a reference of an HTML dialog element. import { useRef } from 'react' const MyModal: React.FC = () ...

Discovering the class type in TypeScript

In my TypeScript coding journey, I encountered a challenge in detecting a specific Class type. Despite its seeming simplicity, I found a lack of straightforward documentation on how to accomplish this task. Here is an example that illustrates the issue: Cl ...

Tips for efficiently utilizing Hooks with React Context:

I am currently working on my application and utilizing React Context with the setState function. const userContext = React.createContext([{ user: {} }, () => {}]); const userHook = useState({ user: {} }); <userContext.Provider value={userHook}> / ...

Encountering incorrect month while utilizing the new Date() object

My Objective: I am looking to instantiate a new Date object. Snippet of My Code: checkDates (currentRecSec: RecommendedSection){ var currActiveFrom = new Date(currentRecSec.activeFrom.year,currentRecSec.activeFrom.month,currentRecSec.activeFrom.day ...

Tips on incorporating express-mysql-session in a TypeScript project

I'm experimenting with using express-session and express-mysql-session in a Typescript project. Here's the relevant snippet of my code: import * as express from "express"; import * as expressSession from "express-session"; import * as expressMyS ...

After defining Partial<T>, encountering an error trying to access an undefined property is unexpected

In my function, I am attempting to standardize certain values by specifying the whole function type as Partial. However, despite declaring the interaction variable as Partial Type, I keep encountering the error message saying "Cannot read property endTime ...

Error: Unable to locate module: Could not find 'react-server-dom-webpack/client.edge'

I've been trying to incorporate server components into my nextJS project, but I keep encountering an issue when using "use server" in my component. Error message: `./node_modules/next/dist/build/webpack/loaders/next-flight-loader/action-client-wrappe ...

Is there a way to verify if an object adheres to a specified interface?

Let's say I have a custom interface called MyInterface Is there a built-in method in TypeScript that allows checking if an object adheres to the MyInterface ? Something similar to using instanceof but for interfaces instead of classes. ...

Returning a 'never' type from a function in React using Typescript

Basically, I have a function that initiates the OAuth flow (redirecting to Google OAuth login page, for example): async function signIn() { // start OAuth flow } And let's say I want to use it in a useEffect hook like this: ... useEffect(() => { ...

"Error encountered: Array is undefined when using the map and subscribe functions in Ionic

I have developed a service that is supposed to retrieve data from a JSON file and assign it to an array called 'countries', which will be used throughout the application on multiple pages. However, when I call the method getCountries, the countri ...

"Encountered an error: Unable to interpret URL from (URL).vercel.app/api/getMessages" while deploying Next.js 13 using TypeScript on Vercel

Hello to all members of the StackOverflow Community: I am encountering an error message stating "TypeError: Failed to parse URL from next-chat-lenx51hr5-gregory-buffard.vercel.app/api/getMessages" while attempting to build my Next.js 13 application using T ...

Download pictures from swift into typescript with the help of share extensions

Currently, I am working on setting up Share Extensions in my ionic3 application. To begin with, I followed these steps: Firstly, I built the app and then launched it in Xcode. After that, I added a Share Extension by navigating to File -> New -> Ta ...

Ditching the subscribe(...) method in Angular by opting to return a string value instead of an

I have been tasked with exploring how to make a service call and return the final result instead of an observable. Within the service, there is a method structured like this: getToken(name: string, pass: string): string { const url = "https://localhost: ...

Navigating the proper utilization of exports and subpaths in package.json with TypeScript

As a newbie in creating npm packages using TypeScript, I've encountered some issues that I believe stem from misinterpreting the documentation. Currently, I am working with Node 16.16.0 and npm 8.13.2. Here is the structure of my project: src/ ├─ ...

How to assign attributes to all child elements in Angular?

I have a unique component in Angular that I utilize throughout my app. It's a button component which I use by calling <app-delete-btn></app-delete-btn> wherever needed. I tried to set the tabindex="1" attribute for my component ...