Enhancing TypeScript functionality by enforcing dynamic key usage

Is there a way to ensure specific keys in objects using TypeScript?

I am attempting to define a type that mandates objects to have keys prefixed with a specific domain text, such as 'create' and 'update':

const productRepoA: Repo = { } // Should fail because create and update keys are missing
const productRepoB: Repo = { productCreate: () => null } // Should fail because update key is missing
const productRepoC: Repo = { productUpdate: () => null } // Should fail because update key is missing
const productRepoD: Repo = { productCreate: () => null, productUpdate: () => null } // Should work because both keys are provided

const orderRepoA: Repo = { } // Should fail because create and update keys are missing
const orderRepoB: Repo = { orderCreate: () => null } // Should fail because update key is missing
const orderRepoC: Repo = { orderUpdate: () => null } // Should fail because update key is missing
const orderRepoD: Repo = { orderCreate: () => null, orderUpdate: () => null } // Should work because both methods are provided

I initially thought that this approach would suffice:

type Repo = {
  [key: `${string}Create`]: () => null
} & {
  [key: `${string}Update`]: () => null
}

However, this implementation allows missing keys like in examples A, B, and C

Answer №1

To address this issue, it is necessary to be explicit in specifying the key:

type Repo<T extends string> = {
  [a in `${T}Update` | `${T}Create`]: () => null
//   [b : `${T}Update`]: () => null
}


const productRepoA: Repo<"product"> = { } // Expected to fail as create and update keys are missing
const productRepoB: Repo<"product"> = { productCreate: () => null } // Expected to fail as update key is missing
const productRepoC: Repo<"product"> = { productUpdate: () => null } // Expected to fail as update key is missing
const productRepoD: Repo<"product"> = { productCreate: () => null, productUpdate: () => null } // Should work as both keys are provided

const orderRepoA: Repo<"order"> = { } // Expected to fail as create and update keys are missing
const orderRepoB: Repo<"order"> = { orderCreate: () => null } // Expected to fail as update key is missing
const orderRepoC: Repo<"order"> = { orderUpdate: () => null } // Expected to fail as update key is missing
const orderRepoD: Repo<"order"> = { orderCreate: () => null, orderUpdate: () => null } // Should work as both methods are provided

Demo: https://www.typescriptlang.org/play?#code/C4TwDgpgBAShYHsA8AVKEAewIDsAmAzlAcAE4CWOA5gHxQC8UA3gLABQUUA2gIZSVQABgBImKAL4BVMHh7ZBUAD5DREgMKkIciIIC6ALigAKAJQM6OAK4Aba+wD09ztwBGUQyLFSZ2vYdPmUFa27OLs4WwAxgg4JFBgpAh4lpHAcIgAgobpyABECUkpwLl0jExQ4lCOUADKABYINnhQAGY85NZQLhCRPJYE0JGa2lA8+FCWPthQANYQIEQ8mlAAtuQEBJRU7NGxwPGJyak5AELZ8HkFR8WlzAeFqRpa2P5m9BY2nZXV9Y3WzW0Ol0en0BhMptA5iB+EQ1hstjsYnErkUcmpzogkPlDkUSgw7ijUtJZC9jG8PrYKlUnL8mq12p1ur1+tBJiTIfMYat1ptqIi9vdrjkACIYy441J4sqCopPbSvQLBawAGhlRIhCveQU+VJ+DTpAHcEKQZsDmWCXAhgHVZvNFssCgA3ch4CB4CK7OLG12kHJZWAXLHeiCkKV3b40-X-elApmgwbDaZjZpskZQ+3QOG87ZRJH7YO+i5nAOY3IFsPlAty0kBLVK3WRv4Ahlm+Pg9m26Hrbnwvm5gUFtFioOkH0VqAF4nysmKnUR2pR5uxkEs9tpzndrMI-te0chkXDst70O3SvH6sQTUUlUT49Tmvk7WU+e06NGk2t1eW62rCDWpIZvczquu6bBAA

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

Place the Div in a consistent position on images of varying widths

I have a dilemma with my class that is supposed to display images. The issue arises when I try to place a div within an image inside this class. Everything works smoothly when the image takes up the entire width of the class, but as soon as the image widt ...

Transform Typescript code into Javascript using webpack while preserving the folder organization

Is there a way for webpack to compile my typescript node project into js while preserving the directory structure and not bundling into one file? This is my current project structure: src |_controllers |_home |_index.ts |_ services ...

Discovering the clicked element within a QueryList<ElementRef> in Angular

Having a ElementRef(QueryList) of a group of dynamically created Table cells (td html elements) using ViewChildren, I have successfully debugged and verified the availability of the element set. When clicking on a specific td html element, a function is c ...

Using Angular: Binding Angular variables to HTML for display

I have a component with a ts file that contains HTML content as a variable. Let's say para1= <a href="www.google.com">sitename</a> more content I want to bind this paragraph in HTML as if it were actual HTML tags. sitename What is the ...

How is it possible for the output to be a string array when the variable was declared as a number in TypeScript?

Snippet: function sampleFunction(sample:string|number|string[]) { if(typeof sample == "string") { console.log("Sample is String " + sample); } else if(typeof sample == "number") { console.log("Sample is Number " + sampl ...

What is the process for retrieving information from a retail outlet?

How can I retrieve data from the Vuex store using Vue.js? Below is my code: Vue.use(Vuex); export default new Vuex.Store({ modules: { data } }) data.js import axios from 'axios'; const state = { data: '' }; cons ...

How can I effectively implement a withAuth higher order component (HOC) in TypeScript within Next.js?

Currently, I am working on a Next.js application and implementing the next-auth package. My goal is to develop a Higher Order Component (HOC) that can determine if the component has an active session or not. Along with this, I am utilizing eslint for code ...

Unable to create property within array in model

I am facing an issue while trying to access the name property of an array called Model[] generated from my Model.ts file. When attempting to use it in my app.component, I receive an error stating that the property 'name' does not exist on type Mo ...

Creating valuable properties in TypeScript is a skill that requires knowledge and practice

In TypeScript, there is a unique feature available for defining properties with values using the `value` keyword. class Test { constructor(private value: number = 123) { } public MyValueProperty: number = 5; } Here is how you can define such ...

Efficiently integrating Firebase Functions with external sub path imports beyond the project's

I encountered an issue in my firebase functions project with typescript. The problem arises when I use types from outside the project with sub path imports, causing the build files to become distorted. Instead of having main:lib/index.js, I have main:lib/ ...

Observables do not provide any results when used in a pipe with an image src

I recently created a custom pipe for the image src in my application: It is applied to selectors like this: <img [src]="myobject?.URL | secure" /> Here's the code snippet for the pipe: import { Pipe, PipeTransform } from '@angular/c ...

What is the best way to integrate retrieved data into Next.js with TypeScript?

Hello everyone! I recently started working with Next.js and TypeScript. Currently, I'm attempting to use the map() function on data fetched from JsonPlaceholder API. Here is my implementation for getStaticProps: export const getStaticProps: GetStatic ...

Modify a single parameter of an element in a Map

Imagine I have a map data type exampleMap: Map<string, any> The key in the map is always a string, and the corresponding value is an object. This object might look like this: { name: 'sampleName', age: 30} Now, let's say the user se ...

Is ngForIn a valid directive in Angular 4?

While attempting to loop over the properties of an object using *ngFor with in, I encountered a challenge. Here is a sample code snippet: @Controller({ selector: 'sample-controller', template: ` <ul> <li *ngFor="let i in o ...

Disable a tab or menu item if the bean's boolean value is 'false'

I designed a home page with various menu/tab options that redirect the user when clicked, but only if they have access to that specific item. If access is not granted, the menu item becomes unclickable. While this functionality works, I am interested in en ...

Verify and retrieve information from the Dynamics CRM Web API with the help of Angular 2 (TypeScript)

How can one authenticate and query the Dynamics CRM Web API from a Single Page Application developed with Angular 2 (TypeScript)? Initial research indicates that: The Dynamics CRM (version 2016 or 365) instance needs to be registered as an application ...

"Troubleshooting Console Errors in NextJS with TypeScript Integration and Fluent UI Components

I am currently working with NextJS, TypeScript, and Fluent UI. To set up the app, I used the command yarn create next-app --typescript. Afterwards, I incorporated Fluent UI into my project by running $ yarn add @fluentui/react. So far, I have not made an ...

What is the process for choosing nested colors from a theme in Material UI?

I have a question regarding how to select a nested style from my theme when creating a Button. Below is the snippet of code that illustrates my dilemma: const buttonStyle: SxProps<Theme> = { '&:hover': { backgroundColor: 'bac ...

conditional operator that compares values in router events

As I examine an object, links = { link1: 'page1', link2: 'page2', link3: 'page3', link4: 'page4', link5: 'page5', link6: 'page6' } I possess a function for retrieving t ...

What is preventing Apollo from achieving full transformation?

I have been struggling with an issue involving Apollo mutation for the past 2 days. Whenever I call a mutation on Angular Apollo generated code and subscribe to it, the subscription never completes. I am expecting a result from the server, but nothing is ...