Combining data types in TypeScript (incorporating new keys into an existing keyof type)

If I have a typescript type with keys:

const anObject = {value1: '1', value2: '2', value3: '3'}
type objectKeys = keyof typeof anObject

and I want to add additional keys to the type without manually defining them, how can I achieve this?
For instance, if I intend to include the keys 'get_value1', 'get_value2', 'get_value3' to the existing type 'objectKeys'

Ultimately, I aim for a type structure like this:

type objectKeys = keyof anObject + 'get_value1', 'get_value2', 'get_value3'

Instead of individually specifying keys prefixed with 'get_', I seek a method to append keys dynamically to the 'objectKeys' type. This is necessary for my specific scenario as typing out all the keys manually is not practical.

I understand that I could create a generic or any type that allows for any key value, but that doesn't serve my purpose. I require the existing keys along with the new ones I wish to include in 'objectKeys'.

Thank you for any assistance provided.

Additional information for clarity:

const anObject = {val1: '1', val2: '2'}
type objectKeys = keyof typeof anObject

Object.keys(anObject).forEach(key => {
  const getAddition = `get_${key}`
  anObject[getAddition] = getAddition
})

// After adding new keys using forEach loop, how do I update objectKeys 
// to reflect these additions?

// My main goal is to update the 'objectKeys' type without altering the 
// keys in the object itself. I want typechecking for the new 'get' values 
// that may or may not exist in the object.

I hope this clarification helps.

Answer №1

It seems like you're inquiring about the ability to concatenate string literal types in TypeScript. This means combining the string literal "get_" with another string literal like "value1" to create the type "get_value1". Unfortunately, as of TypeScript 2.4 (and likely not in future versions 2.5 or 2.6), this feature is not available 🙁.

As a result, strict type safety cannot be maintained if you wish to pursue this approach. A workaround would involve relaxing type safety to allow access for any unknown key:

const anObject = {val1: '1', val2: '2'};
const openObject: { [k: string]: any } & typeof anObject = anObject;

Object.keys(openObject).forEach(key => {
  const getAddition = `get_${key}`
  openObject[getAddition] = getAddition
})
openObject.val1 = 1; // error, val1 is known to be a string
openObject.get_val1 = 1; // no error, get_val1 is any
openObject.gut_val4 = 1; // no error, oops, sorry

However, if you prefer not to take this route, consider organizing the getters under a single get property:

const anObject = { val1: '1', val2: '2' }

type AnObject = typeof anObject;
type ObjectKeys = keyof AnObject;
type GetAugmentedObject = AnObject & { get: Record<ObjectKeys, any> }; 

const get = {} as GetAugmentedObject['get'];
Object.keys(anObject).forEach((key: ObjectKeys) => get[key] = key);
const augmentedObject: GetAugmentedObject = { ...anObject, get }

augmentedObject.val1; // ok
augmentedObject.val2; // ok 
augmentedObject.get.val1; // ok
augmentedObject.get.val2; // ok
augmentedObject.get.val3; // error, no val3
augmentedObject.git.val1; // error, no git

This method may not alter developer usage much (obj.get.val1 vs. obj.get_val1), but greatly aids TypeScript's understanding. If possible, opt for a TypeScript-friendly approach to save time and avoid potential conflicts.

If string concatenation at the type level is crucial for your needs, consider expressing your case on the related GitHub issue with a 👍 and detailed explanation.

Hope this guidance proves helpful. Best of luck!

Answer №3

You have the option to utilize template literals in your code.

Consider the following scenario where the id property should be formed by appending # before the key:

interface CustomInterface<K extends string> {
    specialProperty: {
        [key in K]: { id: `#${key}` }
    }
}

Therefore, this is the appropriate implementation:

let example: CustomInterface<'bar'> = {
    specialProperty: {
        bar: { id: '#bar' }
    }
}

However, this approach would be incorrect:

let incorrectExample: CustomInterface<'bar'> = {
    specialProperty: {
        bar: { id: 'bar' }
    }
}

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

Using the .each method in AJAX JQUERY to iterate through callback JSON data and applying an if statement with Regular Expression to identify matches

Implementing a live search feature using ajax and jQuery involves running a PHP script that returns an array of database rows, encoded with JSON, based on the textfield input. This array is then iterated through in JavaScript after the callback function. ...

Odd behavior observed while running npm scripts in the npm terminal

Included in my package.json file are the following dependencies: "devDependencies": { "chromedriver": "^2.37.0", "geckodriver": "^1.11.0", "nightwatch": "^0.9.20", "selenium-server": "^3.11.0" }, "scripts": { "e2e": "nightwatch -c test ...

What is the best method for submitting a form via ajax that has already been loaded using ajax, all without needing to refresh the current

I have been struggling with a problem for almost a week now. I need to submit a form using ajax, which was already loaded with ajax. I have tried multiple solutions but nothing seems to work. If anyone knows the right approach, I would greatly appreciate y ...

The background color of the active tab is updated upon loading the page

I have attempted to modify this code to change the background color of li tag on click. It successfully changes the background color when hovering or clicking, but unfortunately reverts back to the default color upon page refresh. I am looking for a soluti ...

Eslint is signaling an error when the keyword "async" is used in the most recent version of Node for Firebase Functions

I'm venturing into using Firebase Functions for my project, but as a newcomer to Javascript, I've been struggling for a week now and hit a roadblock with the following issue. Below is the snippet of my code: exports.postcleanup = onSchedule("eve ...

Exploring the concept of nested arrays in Angular 2 using Typescript

I'm exploring the possibility of defining an array in Angular 2 that contains multiple other arrays within it. To clarify, here's what I had initially: export class PaymentDetails { account: any[]; bpNumber: number; } The issue with t ...

Searching for the position of different size values according to their specific value

information = { boxNoTo: 1, boxNoFrom: 1, size: 'M', } items = [{ size: 'M', },{ size: 'M', },{ size: 'S,M,L,XS', boxNoTo: 1, boxNoFrom: 1, country: 'CA', name: 'Josh' }] This is what I have don ...

Issue with MUI Autocomplete not showing selected name on initial option selection

I encountered a strange issue with the Autocomplete component from Material UI. Here is the code snippet in question: const [isContactListInitialised, setContactListInitialised] = useState(false); const toggleContactListInitialized = () => { setContactL ...

Problems with implementing JavaScript code in a WebView

I am currently working on an android WebView project where I have managed to change the background color to orange with this code snippet. @Override public void onPageFinished(WebView view, String url) { wv.loadUrl("jav ...

Utilizing a Typescript class interface does not maintain the original method types

Struggling to define a Typescript interface and implement it in a class. The issue lies in the method signatures of the interface not being applied to the class as expected. Below is a simplified example: export interface Foo { bar(value: string): voi ...

I encountered difficulty displaying a list of documents in the view while working with derbyjs

Exploring derbyjs for the first time, unsure if I'm missing something or if there's a lack of documentation. My model is named "books" and I'm attempting to display a list of books. Here is my code snippet: module.exports = { propertie ...

Is it possible to extract form data from a div tag based on its class name?

I'm working with some code that looks like this: var iconContainer = document.getElementById('iconContainer'); var icon = iconContainer.getElementsByClassName("item"); for (var i = 0; i < icon.length; i++) { icon[i].addEventListener ...

What is the best way to add an image using php, javascript, and browser storage?

Previously, I successfully uploaded an image using PHP and HTML. Now, I need to achieve the same with JavaScript (js) and AJAX. Additionally, I have been advised to utilize local storage for server-side storage before inserting it into the database. Below, ...

JavaScript Image Swap

I tried implementing this script but it didn't work for me. I'm not sure what to do next, so I'm reaching out for help. The script is at the top of the page, followed by a picture with an id that I'd like to change when a button below i ...

Tips for incorporating Javascript in an innerHTML inline css situation

I'm just starting to learn about html5 and php. I'm curious about how to incorporate javascript into my existing code. Currently, I have data from a database displayed in an HTML table. My goal is to align the output of the last cell more toward ...

Struggling to clear items from input field within AngularJS

I'm currently facing an issue where I am unable to delete data from an input field. var myApp = angular.module('myApp',[]); myApp.controller('MyCtrl', function MyCtrl($scope) { $scope.items = [ { name: & ...

Do overlay elements have to be positioned at the bottom of the HTML body every time?

As I delve into the world of JavaScript frameworks, one common trend I've noticed is that elements like dialogs, tooltips, and alerts usually appear at the end of the body tag. With my own implementation of these UI elements, I am determined to make ...

Submitting the form without utilizing Ajax, but instead sending data directly to a PHP script

I've encountered an issue while posting a form to a PHP file using AJAX. Despite my efforts, the form is bypassing AJAX and posting directly to the PHP file. Here is my form: <form id="editform" name="editform" action="ajaxeditform.php" method= ...

Top method for identifying browser window modifications such as navigating back, altering the URL, refreshing, or closing the window

Currently, I am developing a testing application that requires me to trigger a finsihTheTest() function in specific situations. These situations include: When the user attempts to reload the page. When the user tries to navigate back from the page. If the ...

Is there a way to determine if a browser supports the offline event?

I attempted to implement the code from this Stack Overflow question: How can I check for support of the `focusin` event? However, in Chromium, the method hasEvent('offline') returns false even though it supports the `offline` event. Does anyone ...