Ensuring that array elements serve as keys within a TypeScript record

How can I define a TypeScript interface with the additional constraint that entries in the 'required' field must be keys of the 'properties' field?

interface ObjectSchema {
  properties: Record<string, any>;
  required: Array<string>;
}

An example of a correctly typed object would be:

let schemaA = {
  properties: {
    foo: {},
    bar: {},
  },
  required: ["foo"]
}

An example of an incorrectly typed object would be:

let schemaA = {
  properties: {
    foo: {},
    bar: {},
  },
  required: ["baz"] // "baz" is not a key in 'properties'.
}

Answer №1

To ensure proper functionality, it is necessary to utilize two type variables: one for the keys within properties, and the other for the subset of keys specified in required.

asObjectSchema serves as a convenient tool to capitalize on inference, thereby eliminating the need for explicit annotation of the type variables.

interface ObjectSchema<A extends string, B extends A> {
  properties: Record<A, any>
  required: Array<B>
}

const asObjectSchema = <A extends string, B extends A>(
  schema: ObjectSchema<A, B>
): ObjectSchema<A, B> => schema

const schemaA = asObjectSchema({
  properties: {
    foo: {},
    bar: {},
  },
  required: ['foo'],
})

const schemaB = asObjectSchema({
  properties: {
    foo: {},
    bar: {},
  },
  required: ['baz'], // Type '"baz"' is not assignable to type '"foo" | "bar"'
})

Playground

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

An unexpected type error arising from using Typescript in conjunction with the useRef hook

I created a unique Checkbox component to manage events differently, see the code snippet below: const DoubleClickCheckbox = ({ filter, handleDoubleClick, handleSingleClick }: DCCheckboxProps) => { const delay = 400; const timer = useRef(null); co ...

Leveraging the ReturnType from a method within a Child class that inherits from an abstract class

I'm encountering an issue where TypeScript is throwing a lot of errors when trying to utilize the ReturnType of a method from an abstract class in a child class. Here's a simple example that illustrates the problem: Thank you abstract class Par ...

Encountered difficulties in deploying functions on Firebase Cloud Functions

While developing the Firebase Cloud Functions, I organized the files based on each function. Unfortunately, numerous errors occurred during deployment. Error [debug] [2022-07-19T14:36:17.677Z] <<< [apiv2][body] GET https://us.gcr.io/v2/xxxxxx/gcf ...

What are the most effective strategies for handling sessions in Ionic 2?

I'm currently working on an app using Ionic 2, but I'm facing some challenges in managing the user session. I want the user to be prompted to enter their credentials every time they open the app. Can someone please provide guidance on how to achi ...

Caution: the use of findDOMNode is no longer supported in StrictMode when utilizing react-bootstrap Navbar

While attempting to utilize the Navbar component from react-bootstrap in a typescript template, I encountered the following warning in the Chrome console. index.js:1 Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of T ...

What is the best way to handle errors that occur asynchronously without using promises in order to respond to those specific errors?

I have searched for answers but none seem to directly address my specific question. My current usage involves the pattern shown below: class A { getLocation() { return Promise.reject(2222222) } async a() { try ...

"Sending an Angular post request results in the transmission of an [object Object

I am a beginner in angular and currently involved in a project using angular 6 with Spring Boot 2. Here is the TypeScript class I am working with: export class Partner { constructor ( public id: number, public name: string, public email: ...

How can I choose one record based on another record in a database?

I have a unique structure where consts and record types are combined: const PageType = [ 'type1', 'type2', 'type3' ] as const; export type PageType = typeof PageType[number]; interface PageInfo { title: string } int ...

Sign in and create an account seamlessly on a single page with React

Looking for a way to integrate login and register functionalities on one page using React with TypeScript. However, facing an issue where the login component briefly displays before switching back to the signup component. Unable to determine why the stat ...

How should a React Testing Library wrapper be properly typed in a TypeScript environment?

There's this code snippet from Kent C. Dodd's library that I find extremely helpful import * as React from 'react' import {render as rtlRender} from '@testing-library/react' import {ThemeProvider} from 'components/theme& ...

Can you explain how parameters are being transferred to the onClick function?

While examining some code, I noticed the following snippet: <temp onClick={this.onSelected} /> The onSelected function appears to be defined like this: onSelected = (id: string) => { [...] } I'm curious how the id: string is being pas ...

The lack of displaying the actual path in DevTools when using RouterLink in Angular 5

Could this be a bug or a specification that I can't seem to find in Angular 5? When I use routerLink in the following way: <button routerLink="/account/order/{{this.orderService.order._id}}/messages">Messages</button> Everything works fi ...

Utilizing list elements as unique identifiers in a Python dictionary

Currently, I am faced with the task of processing a large CSV file in Python and my goal is to generate a dictionary based on text lists associated with unique identifiers. Within the CSV file, the content of each cell under the Items column was initially ...

Exploring the different types of arguments in GraphQL Apollo server resolvers

The error in the TypeScript script is due to not specifying argument types for each argument: Mutation: { createUser: (parent, args, context, info) =>{ } To solve this issue, I could use any type, but what are the correct types to specify? ...

What is the method to utilize @template in JSDoc function in order to establish consistency between parameter and return types?

When working on an ecmascript project, I make use of @ts-check and a ts linter to follow TypeScript's formalism without actually using TypeScript itself. Everything is running smoothly except for one issue: I am trying to implement JSDoc generics dec ...

Execute various Office Scripts functions within a single script based on the button that is selected

Imagine you have an Excel spreadsheet with two buttons named populate-current and populate-all. Both buttons execute the same Office Script function that looks something like this: function populateByRowIndex(workbook: ExcelScript.Workbook, rowIndex: numbe ...

Increasing an ID number automatically using Javascript

I'm currently working on a functionality where a unique number is automatically generated whenever a new record is created. For instance, if I were to click "Create record" on a webpage, the number would auto-fill in the record ID field. Subsequently, ...

Can you explain the distinction between @types/material-ui and the official @mui/types bundle?

When it comes to npm packages, I came across @types/material-ui and @mui/types. I'm aware that the former is backed by the Definitely Typed community, but what's the reasoning behind its existence when an official types package already exists? D ...

Angular 2 forms are displaying ngvalid when input fields are marked as nginvalid

The form displays ngvalid because I have included the code like this: <form novalidate class="pop-form" (submit)="signUp()" #regForm="ngForm"> <div class="group"> <input type="text" [(ngModel)]="signUpData.name" [ngMode ...

Create an HTML button on the homepage that directs users to the "about" page

I've been struggling to make a button in my Ionic app navigate to a different page upon clicking. Despite being new to Ionic, I've spent hours trying to solve this issue. Below is the HTML code in home.page.html: <ion-header> &l ...