Creating a data type restricted to utilizing property names exclusively from a specified string union:

I have a specific Enum:

enum MyEnum {
  optionOne = 0,
  optionTwo = 1,
  optionThree = 2,
  optionFour = 3,
}

and a related Type:

export type EnumNamesList = keyof typeof MyEnum;

I am looking to create a type similar to this:

export type EnumDataTypes = {
    optionOne: string;
    optionTwo: boolean;
    optionThree: Date
}

while making sure that all property names are of type EnumNamesList.

Any ideas or suggestions on how to achieve this?

I attempted the following approach:

export interface EnumData extends Record<EnumNamesList, any> {
    optionOne: string;
    optionTwo: boolean;
    optionThree: Date
}

however, this code results in a compilation error:

export interface EnumData extends Record<string, Date> {
    optionOne: string;
}

this one does not throw an error:

export interface EnumDataExample extends Record<EnumNamesList, any> {
    notValid: string;
}

The main objective is to have a class structured like so:

class MyClass<TypeDefinitions extends Partial<Record<EnumNamesList, any>>>{

  fetchValue<T extends EnumNamesList>(name: T): TypeDefinitions[T]{
    return {} as any;
  }
}

where a defined type is passed to specify the return types of the fetchValue function. It should only be feasible to define recognized property values within that type while still allowing for partial types to be passed through.

Answer №1

Preventing additional properties can pose a challenge, and Typescript doesn't make it easy.

I believe this solution might be your best option:

class SomeClass<TypeLookup extends Partial<Record<EnumNames, unknown>>>{
  getValue<T extends keyof TypeLookup & EnumNames>(name: T): TypeLookup[T]{
    return {} as any;
  }
}

Now this behaves as expected:

new SomeClass<{ nameOne: string }>().getValue('nameOne') // perfect
new SomeClass<{ nameOne: string }>().getValue('nameThree') // error
new SomeClass<{ notValid: string }>() // error

The only change made was with the constraint of T in the getValue method. Now it must be a key within the TypeLookup generic parameter, intersected with the keys from the original enum. This ensures that T will always be a subset of keys from both SomeEnumIds and the type passed in.


One thing to note is that extra keys are only rejected if they are passed in directly. However, because getValue is restricted to the keys of the original enum, you won't be able to access those properties using the getValue method.

type SomeType = { nameOne: string, notValid: string }
new SomeClass<SomeType>().getValue('nameOne') // fine
new SomeClass<SomeType>().getValue('notValid') // error

This is likely the best solution you'll find, as attempting to have new SomeClass<SomeType> resolve to never by utilizing precise types would only result in downstream type errors.

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

What is the best approach to implementing a blur function for a specific input within a parent component?

I have created a custom input field as a separate component. I want to include multiple input fields in the parent component using directives: <app-input ...></app-input> My goal is to pass the blur event/function to the parent component speci ...

Combining 2 lists in Angular Firebase: A Simple Guide

I have been searching for a solution for the past 2 hours, but unfortunately haven't found one yet. Although I have experience working with both SQL and NoSQL databases, this particular issue is new to me. My problem is quite straightforward: I have t ...

Exploring the Integration of OverlayScrollbars with TypeScript

Currently, I am delving into TypeScript utilizing a project built on ASP.NET Core 3.0 and the VS 2019 IDE. Recently, I acquired the OverlayScrollbars plugin via npm: . npm install overlayscrollbars npm install @types/overlayscrollbar Provided below is a ...

Component declaration in Typescript is being rejected due to the union type not being accepted

In my current project, I'm working on a component that should accept either an onClick or a to prop. const StickyButton: React.FC< ({ onClick: MouseEventHandler } | { to: string }) & { buttonComponent?: ({ onClick: MouseEventHandler }) =& ...

Error: Unable to Locate Module (Typescript with baseUrl Configuration)

Struggling to implement custom paths in my TypeScript project, I keep encountering the "webpackMissingModule" error due to webpack not recognizing my modules. I've attempted various solutions without any success. Any suggestions or ideas? Some packa ...

What are the differences between TypeScript's 'Dictionary' type accessors for objects and objects with predefined members?

Currently, I am delving into TypeScript by following an online tutorial. While my programming background primarily consists of 'structurally' typed languages like C and ActionScript 3, TypeScript presents some new concepts for me to grasp. One p ...

The validation using regex is unsuccessful when the 6th character is entered

My attempt at validating URLs is encountering a problem. It consistently fails after the input reaches the 6th letter. Even when I type in "www.google.com," which is listed as a valid URL, it still fails to pass the validation. For example: w ww www ww ...

How can I transfer an instance of a class to dataTransfer.setData?

So I created a new instance of a class: let item = new Item(); Next, I attempted to serialize the item and add it to dataTransfer for drag and drop functionality: ev.dataTransfer.setData("info", JSON.stringify(item)); At some point, I need to retriev ...

Binding data to custom components in Angular allows for a more flexible

In my current scenario, I am looking to pass a portion of a complex object to an Angular component. <app-component [set]="data.set"></app-component> I want the 'data.set' object in the parent class to always mirror the 'set&apo ...

Is there a way to verify the availability of an authenticated resource without triggering a pop-up for credentials in the browser?

I am facing the challenge of fetching data from a web service located on a different server without knowing if the user has an active session on that server. If the user does have a session, I want to retrieve the data automatically. However, if they do no ...

Retrieving the component's values when utilizing the `<ng-content>` directive

Seeking a technique for accessing the values of a component when utilizing <ng-content>: import {Component} from '@angular/core'; @Component({ selector: 'home-page', template: `<person-box>{{name}}</person-box> & ...

Angular HTTP Patch method requires explicitly defined HTTP options as input parameters

I encountered a challenge with using Angular's HTTP patch method and noticed that the overloaded function patch(url, body, options) only accepts hardcoded values for HTTP options. An example of a hardcoded approach that works: patchEntity(id: number) ...

Guide to making a TreeView in Angular 2 with Typescript

How can I implement a TreeView in Angular 2 using Typescript? I have searched on Google but have not found any working examples, etc. Could someone kindly provide me with an example to help me accomplish this task? ...

Ways to define an interface that can accommodate various interfaces with a specific structure

I am in need of a function that can accept a parameter with interfaces having a specific structure. The parameter should be either a string hash or a string hash along with an attribute string hash, as shown below: { anotherHash: { a: 'a', ...

Issue with RouterLink not recognizing QueryParams

I have encountered an issue where dynamically generated URLs with queryParams inside [routerLink] are breaking routes. For example: this.url = '/question/ask?details=1' <a [routerLink]="url"> {{ data.name }}</a> Upon mouseover, the ...

Sending data to Dialog Component

While working on implementing the dialog component of material2, I encountered a particular issue: I am aiming to create a versatile dialog for all confirmation messages, allowing developers to input text based on business requirements. However, according ...

Retrieve the TaskID of an ECS Fargate container for exporting and future use within AWS CDK code

Currently, I am leveraging CDK version 2 alongside Typescript. In my current setup, I encounter a situation where I necessitate the TaskID value from ECS Fargate Container to be incorporated into another command. The process involves me utilizing new ecs ...

Schedule - the information list is not visible on the calendar

I am trying to create a timeline that loads all data and events from a datasource. I have been using a dev extreme component for this purpose, but unfortunately, the events are not displaying on the calendar. Can anyone offer any insights into what I might ...

What could be causing the malfunction of the Bootstrap5 modal hide feature?

Today, I am facing an issue with hiding the Bootstrap5 modal in a TypeScript function. Despite trying to invoke the hide function on the modal element, it does not work as expected. Here is the minimal code snippet to reproduce this problem: import React f ...

Using Rxjs to reset an observable with combineLatest

My scenario involves 4 different observables being combined using "combineLatest". I am looking for a way to reset the value of observable 2 if observables 1, 3, or 4 emit a value. Is this possible? Thank you! Mat-table sort change event (Sort class) Mat- ...