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

formik connects props that are lacking certain properties

Trying to figure out a way to simplify the process of declaring all the properties of formik in my Props when using connect(). The error message I keep encountering is: Type '{ entry: Entry; }' is missing the following properties from type &apos ...

Running out of memory due to inefficient mark-compacting processes nearing the heap limit in Angular 8 allocation

A significant portion of the modules are built, with only one active in progress. The process is located at ...\src\index.js??extracted!D:\Clients\app\node_modules\sass-loader\lib\loader.js??ref--15-3!D:\src&bso ...

Is it possible to verify or authenticate the properties received directly from the associated type or interface?

Looking for a more efficient way to handle validation in my component that takes an array of tabs and children as props. I would like to check if the children provided are the same length as the tabs array directly from the type declaration or any cleaner ...

How can TypeScript objects be serialized?

Is there a reliable method for preserving type information during JSON serialization/deserialization of Typescript objects? The straightforward JSON.parse(JSON.stringify) approach has proven to have several limitations. Are there more effective ad-hoc sol ...

Encountered error E404 during installation of react packages using npm

Encountering an error while developing a Typescript-based fullstack project. The error message is as follows: npm ERR! code E404 npm ERR! 404 Not Found - GET https://registry.npmjs.org/@mui%2ficon-material - Not found npm ERR! 404 npm ERR! 404 '@mui ...

Create an eye-catching hexagon shape in CSS/SCSS with rounded corners, a transparent backdrop, and a

I've been working on recreating a design using HTML, CSS/SCSS in Angular. The design can be viewed here: NFT Landing Page Design Here is a snippet of the code I have implemented so far (Typescript, SCSS, HTML): [Code here] [CSS styles here] [H ...

Implementing Service Communication

I created an Angular Application using the Visual Studio Template. The structure of the application is as follows: /Clientapp ./app/app.module.shared.ts ./app/app.module.client.ts ./app/app.module.server.ts ./components/* ./services/person-data.service. ...

Use contextual type when determining the return type of a function, rather than relying solely on

When using Typescript 2.2.2 (with the strictNullChecks option set to true), I encountered an unexpected behavior. Is this a bug or intentional? interface Fn { (value: any): number; } var example1: Fn = function(value) { if (value === -1) { ...

Leverage the power of forkJoin in JavaScript by utilizing objects or sourcesObject

I'm currently facing an issue with my code snippet below: getInformations().subscribe( informations => { let subs = []; for (const information of informations) { subs.push(getOtherDetails(information.id)); } ...

The server has access to an environment variable that is not available on the client, despite being properly prefixed

In my project, I have a file named .env.local that contains three variables: NEXT_PUBLIC_MAGIC_PUBLISHABLE_KEY=pk_test_<get-your-own> MAGIC_SECRET_KEY=sk_test_<get-your-own> TOKEN_SECRET=some-secret These variables are printed out in the file ...

Invoking vscode Extension to retrieve data from webview

One task I'm currently working on involves returning a list from the extension to be displayed in the input box of my webview page. The idea is for a JavaScript event within the webview to trigger the extension, receive the list object, and then rend ...

Tips on converting a date string in the format 'dd/MM/yyyy' to a date type using TypeScript

I have attempted the following code in order to convert the date from 'yyyy-mm-dd' format to 'dd/MM/yyyy'. However, when I check the typeof() of the result, it shows that it is a string. Is there a method to convert it into only a date? ...

JS- Catching Errors Inside and Outside

Imagine having 2 catch blocks in your code: try { axios.get('https://example.com', {}) .then(function (responseOne: any) { return axios.post('https://example.com', {}, {}) }).then(async function (responseTwo: any) { return a ...

TypeScript overload does not take into account the second choice

Here is the method signature I am working with: class CustomClass<T> { sanitize (value: unknown): ReturnType<T> sanitize (value: unknown[]): ReturnType<T>[] sanitize (value: unknown | unknown[]): ReturnType<T> | ReturnType< ...

"Using Angular and TypeScript to dynamically show or hide tabs based on the selected language on a website

When switching the language on the website, I want to display or hide a specific tab. If the language is set to German, then show the tab; if any other language is selected, hide it. Here's my code: ngOnInit(): void { this.translate.onLangChange.s ...

Avoiding circular imports in Angular modules

After restructuring my angular app from a monolithic shared feature module to smaller ones, I faced a challenge with what appears to be a cyclic dependency. The issue arises when I have components such as triggerA, modalA, triggerB, and modalB interacting ...

Tips for utilizing the keyword 'this' within a Promise

Seeking assistance with resolving an issue involving an undefined error when attempting to make an http request within a Promise function. The error occurs due to this.http.post being undefined, indicating that there is an issue with accessing this properl ...

Guide to upgrading ag-grid-community from 20.1.0 to 24.1.0

I'm currently encountering some errors that I can't seem to find in the AgGrid documentation. These attributes are not mentioned anywhere, not even in the Change Log. First off, these compilation errors are popping up: ERROR in : Can't bind ...

Pass the type of object property as an argument in the function

I've been having trouble trying to figure this out and haven't been able to find a solution in the TS docs or examples I came across. Essentially, I'm working with a configuration specifying operations on object properties and looking to en ...

I thought enabling CORS would solve the issue, but it seems like the restrictions

This is my setup for an asp.net core web API: public void ConfigureServices(IServiceCollection services) { services.AddCors(o => o.AddPolicy("CorsPolicy", builder => { builder ...