Can Typescript restrict a value to only exist within a specified set of key names within the same object?

I am completely new to Typescript and I am fascinated by the way it can check types.

One thing I would like to know is if Typescript can be used to verify at compile time whether a value's domain falls within a predefined set of key names that are declared in the same object?

Let me provide an example to better explain my question. Here are some object and type definitions:

type ElemField = { name: string }
type Elem = Record<string, ElemField>

type Relation = { path: string[] }

type MySchema = {
    elem: Record<string, Elem>,
    relations: Record<string, Relation>
}

const test: MySchema = {
    elem: {
        elem1: {
            prop1: { name: 'string' },
        },
        elem2: {
            prop2: { name: 'string' },
            prop3: { name: 'string' },
        },
        elem3: {
            prop4: { name: 'string' },
        }
    },
    relations: {
        relation1: {
            path: ['elem2', 'elem1'],
        },
        relation2: {
            path: ['elem3', 'elem1'],
        }
    }
}

I am curious to know if it is feasible to validate at compile time whether the path array only includes values that match keys from the root level elements object.

I am unsure if features like keyof, generics, or other advanced Typescript functionality can help achieve this kind of validation.

EDIT: A big thank you to Shahriar Shojib for providing a helpful solution. However, I still wonder if there is a way to accomplish this without using a function, but rather by strictly specifying the object's type.

Answer №1

If you are looking for alternate methods to accomplish this task, there may be more efficient approaches available. However, the following code snippet should suffice for your specific scenario.

type ElementField = { name: string }
type Element = Record<string, ElementField>

type Relation<T> = { path: T[] }

type CustomSchema<T extends Record<string, Element>>  = {
    element: T,
    relations: Record<string, Relation<keyof T>>
}

function generateCustomSchema<T extends Record<string, Element>>(schema: CustomSchema<T>) {
    return schema;
}

generateCustomSchema({
    element: {
        item1: {
            feature1: { name: 'string' },
        },
        item2: {
            feature2: { name: 'string' },
            feature3: { name: 'string' },
        },
        item3: {
            feature4: { name: 'string' },
        }
    },
    relations: {
        connection1: {
            path: ['item2', 'item1', 'item5'], // Results in an error as it does not exist
        },
        connection2: {
            path: ['item3', 'item1'],
        }
    }
})

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

What are the potential downsides of using ID to access HTML elements in React TypeScript?

During my previous job, I was advised against accessing HTML elements directly in React TypeScript using methods like getElementById. Currently, as I work on implementing Chart.js, I initially used a useRef hook for setting up the chart. However, it appear ...

Steps to develop a collaborative NPM package

I am currently in the process of developing an NPM package using Typescript that contains solely my type interfaces. At the moment, my project has the following folder structure: project │ index.ts │ └───types │ restaurant.ts │ ...

Struggling to access the properties of a Material-UI Button

import * as React from "react"; import { styled } from "@mui/material/styles"; import MuiButton from "@mui/material/Button"; import Slider from "@mui/material/Slider"; interface Props { type: "primary" | ...

How can I store various data types in a single array in TypeScript?

I have a scenario I need help with. Let's say we have two interfaces, Cats and Dogs. How can I create an array that can store both Cats and Dogs? interface Cats { name: string; age: number; } interface Dog { owner: string; } const cat1: Cat ...

What is the best method for implementing Datepicker translations in Angular?

I am looking to incorporate the DatePicker component in Angular, enabling users to select a date that can be translated based on their browser's settings. Any suggestions on how to achieve this? <mat-form-field appearance="fill"> ...

"Encountering a problem when trying to display Swagger-Editor for the second

While integrating the swagger-editor package into my React application, I encountered an issue. The first time I fetch the Swagger specifications from GitHub, everything works perfectly and validates correctly. However, upon rendering it a second time, an ...

Issues with mat-tab-group not rendering properly after switching between parent tabs

I am facing an issue involving nested tabs and tables in my example. Check out the example here After switching between parent tabs and child tabs, there seems to be an issue where the tabs do not render properly. It takes multiple attempts of switching ...

After inputting the required parameters for the React onChange event, an unexpected error persists despite my efforts

I'm struggling with a bug in my React / typescript code. I have created a custom Input component that includes an 'onChange' property as described below: onChange?: (value?: string, event?: React.ChangeEvent<any>) => void; Here is ...

Tips for integrating jwt token into axios request

I am facing an issue with my backend endpoint. I can successfully retrieve a list of customers using jwt token on Postman, but when I try to fetch the list from a React app using axios get request, it fails. After reading through this question, I implemen ...

Leveraging angular2-material with systemjs for Angular2 development

After completing the TUTORIAL: TOUR OF HEROES on this link, I attempted to integrate angular2-material into my project. Unfortunately, I am having issues with the CSS not displaying correctly. Can anyone provide insight into what I may be missing or doing ...

Angular 7 ESRI loader search widget focus out bug: finding a solution

I am currently working on implementing an ESRI map using esri-loader in my Angular application. Everything seems to be working fine, but I am encountering an error when typing something into the search widget and then focusing out of it. "Uncaught Typ ...

Guide on linking an XML reply to TypeScript interfaces

Currently, I am faced with the task of mapping an XML response (utilizing text XMLHttpRequestResponseType) from a backend server to a TypeScript interface. My approach has been to utilize xml2js to convert the XML into JSON and then map that JSON to the Ty ...

Upgrading my loop React component from vanilla JavaScript to TypeScript for improved efficiency and functionality

After seeking assistance from Stack Overflow, I successfully created a loop in React using a functional component that works as intended. However, I am encountering errors while trying to refactor the loop to TypeScript. The code for my DetailedProduct c ...

Troubleshooting: Resolving the Error "Cannot find Property htmlFor on Custom React Component"

I am currently working with a custom component that looks like this: import React from "react"; import classnames from 'classnames'; import { ButtonVariantColor } from '../types/button'; export type IconButtonProps = { e ...

Issue: The function (0, react__WEBPACK_IMPORTED_MODULE_1__.useActionState) is not recognized as a valid function or its output is not iterable

I found a great example of using useActionState at this source. Currently, I am implementing it in my project with Next.js and TypeScript. app/page.tsx: "use client"; import { useActionState } from "react"; import { createUser } from ...

InjectableToken missing in Angular Standalone Component - Provider Not Found

In my standalone component, I am using an Injection Token to set a path (the paths are not the same for all micro-frontends). However, I do not provide this token in the component itself because I need to override it using providers in my app-module.ts. H ...

Setting up ESLint and Prettier with TypeScript on Node 20: A Guide

I attempted to set up Prettier with ESLint and crafted a configuration in settings.json to rectify errors upon saving, but the errors only manifest in .js files and not .ts files. How can I adjust this? Dependencies: "@eslint/js": "^9.4.0& ...

Tips for including an authorization token in an HTTP request

I encountered a 401 unauthorized error when trying to access my REST endpoint, likely due to the security measures I have implemented. I suspect that there might be an issue with how I am handling the HTTP headers. The application utilizes a Spring Boot b ...

Verifying TypeScript errors before each commit in a Vue application

We have set up a git hook in our app using Husky for pre-commit actions. Whenever someone commits code, it triggers the pre-commit code - #!/bin/sh . "$(dirname "$0")/_/husky.sh" export NVM_DIR="$HOME/.nvm" [ -s "$NVM_ ...

Angular2 webpack example error: Cannot execute function 'call' because it is undefined

As I navigate through the Angular2 webpack sample app on https://angular.io/docs/ts/latest/guide/webpack.html, I've encountered an issue. After completing the "Development Configuration" section and attempting the "try it out" by copying the app code ...