Is there a way to inform TypeScript that an object can only return properties from values found within an array?

I am trying to ensure that the return object from a function in TypeScript only allows keys that correspond to string values present in an array passed as an argument to the function. The returned object should contain a subset of keys from a list of valid strings based on the input array. I am struggling with referencing the actual values provided to 'myArr'.

declare type ListOfStrings = 'apple' | 'banana' | 'car';
function doSomething(myArr: ListOfStrings[]) {
    const returnObj: { [Properties in ListOfStrings]?: number } = {}; 
    for (const entry of myArr) returnObj[entry] = Math.random();
    return returnObj;
}

const finalObj = doSomething(['banana', 'car']);
console.log(finalObj.apple); // This does not generate a TypeScript error, which is what I want help with.

Any advice would be greatly appreciated!

Answer №1

If you want to ensure the correct structure of your object, consider making your function generic

function createObject<T extends ArrayOfStrings>(myArr:T[] ) {
    const resultObj: { [Property in T]?: number } = {}; 
    for (const item of myArr) resultObj[item] = Math.random();
    return resultObj;
}

This approach will guarantee that the resulting object follows the desired format

const newObj = createObject(['apple', 'truck']);
const newObj: {
   apple?: number | undefined;
   truck?: number | undefined;
}

Answer №2

Employ Generics in tandem with Mapped Types.

type ListOfFruits = 'apple' | 'banana' | 'car';

function processItems<
    T extends ListOfFruits,             // Ensure the items in `arr` are part of this union.
    K extends Extract<ListOfFruits, T>  // Extract only the values included in the `arr`.
>(arr: T[]){
    const result = {} as { [k in K]: number }; // Map union `K` to return value properties.

    for (const entry of arr){
        result[entry as K] = Math.random();    // Indicate to the compiler that the value of `arr` is one of K.
    }

    return result;
}

const valid = processItems(['banana', 'car']);  // valid
valid.banana; // valid
valid.orange; // error

const invalid = processItems(['banana', 'orange']);  // error

See Demo in playground.

Answer №3

Not flawless, but it should do the job

function performAction<Keys extends string>(keys: Keys[]): Partial<Record<Keys, number>> {
    const returnObject: Partial<Record<Keys, number>> = {};
    for (const item of keys) {
        returnObject[item] = Math.random();
    }
    return returnObject;
}

const result = performAction(['alpha', 'beta']);
result.c // error

TypeScript Playground Link

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

Easy Steps to Simplify Your Code for Variable Management

I currently have 6 tabs, each with their own object. Data is being received from the server and filtered based on the tab name. var a = {} // First Tab Object var b = {} // Second Tab Object var c = {} // Third Tab Object var d = {}// Fou ...

Fixing the "Cannot find name" error by targeting ES6 in the tsconfig.json file

I recently started learning AngularJS through a tutorial. The code repository for the tutorial can be accessed at this link. However, upon running npm start using the exact code provided in the tutorial, I encountered the following error: Various TS2304 e ...

Using TypeScript with Watermelondb

I'm currently developing a React App and I want to implement Watermelondb for Offline Storage, but I'm unsure about using it with TypeScript. I have already set up the database and created Course and Lesson model files from the Watermelondb libra ...

How do I manage 'for' loops in TypeScript while using the 'import * as' syntax?

When working with TypeScript, I encountered an issue while trying to import and iterate over all modules from a file. The compiler throws an error at build time. Can anyone help me figure out the correct settings or syntax to resolve this? import * as depe ...

Utilizing Typescript's baseUrl compiler configuration for node development

Is there a way for node's module loader to support TS's baseUrl compiler option? With the introduction of the baseUrl compiler option in TS 2, project relative require() and import requests are now possible. However, this feature requires that ...

Checking a sequence using a list of strings

I have an array containing a list of IDs: var listId: string[] = []; var newId: boolean; for (let i in data.chunk) { listId.push(data.chunk[i].aliases[0]); } My objective is to compare a new ID with the entire list. If the new ID is found in the list ...

Dealing with server-side errors while utilizing react-query and formik

This login page utilizes formik and I am encountering some issues: const handleLogin = () => { const login = useLoginMutation(); return ( <div> <Formik initialValues={{ email: "", password: "" }} ...

Ways to "Compile out" log commands

In my typescript project, there is a section of code dedicated to creating debug information. However, upon profiling the application, I discovered that this debug code is causing a significant performance impact. Currently, my approach involves setting a ...

Tips for setting up a full-size image with nextJS and the <Image /> component

Upgrading NextJS to the latest version has resulted in some errors when using the Image component: // import Image from 'next/image' <div style={Object.assign({}, styles.slide, style)} key={key}> <Image src={src} alt="&quo ...

What is the best way for a parent process to interrupt a child_process using a command?

I'm currently in the process of working on a project that involves having the user click on an 'execute' button to trigger a child_process running in the backend to handle a time-consuming task. The code snippet for this operation is shown b ...

Determine whether there is only one array in the object that contains values

At the moment, I am attempting to examine an array in order to determine if only one of its elements contains data. Consider this sample array: playersByGender = { mens: [], womens: [], other: [] }; Any combination of these elements may contain dat ...

Updating a subscribed observable does not occur when pushing or nexting a value from an observable subject

Help needed! I've created a simple example that should be working, but unfortunately it's not :( My onClick() function doesn't seem to trigger the console.log as expected. Can someone help me figure out what I'm doing wrong? @Component ...

Can TypeScript automatically deduce keys from a changing object structure?

My goal here is to implement intellisense/autocomplete for an object created from an array, similar to an Action Creator for Redux. The array consists of strings (string[]) that can be transformed into an object with a specific shape { [string]: string }. ...

Experiencing unexpected output from Angular model class method

I have developed a user-friendly Invoicing & Inventory management application that showcases a list of invoices for each customer. However, there seems to be an issue with the calculation of the Grand Total function, which I am struggling to rectify due to ...

What is the best way to map elements when passing props as well?

In my code, I am using multiple text fields and I want to simplify the process by mapping them instead of duplicating the code. The challenge I'm facing is that these textfields also require elements from the constructor props. import React, { Compon ...

Ways to import a library in JavaScript/TypeScript on a web browser?

I'm currently working on a project that involves a TypeScript file and an HTML page. Right now, I am loading the necessary libraries for the TypeScript file in the HTML Page using script tags like <script src="https://unpkg.com/<a href="/cd ...

Altering a public variable of a component from a sibling component

Within my application, I have two sibling components that are being set from the app.component: <my-a></my-a> <my-b></my-b> The visibility of <my-a> is determined by a public variable in its component: @Component({ module ...

Using TypeScript to automatically deduce the output type of a function by analyzing the recursive input type

I am currently working on developing an ORM for a graph database using TypeScript. Specifically, I am focusing on enhancing the "find" method to retrieve a list of a specific entity. The goal is to allow the function to accept a structure detailing the joi ...

Error in TypeScript on SendGrid API: Invalid HttpMethod

Here is my code snippet: import sendgridClient from '@sendgrid/client' sendgridClient.setApiKey(process.env.SENDGRID_API_KEY); const sendgridRequest = { method: 'PUT', url: '/v3/marketing/contacts', bo ...

What is the best way to perform an AJAX request in Typescript with JSON data?

Currently, I am delving into the realm of AJAX and encountering some hurdles when attempting to execute an AJAX request with parameters. Specifically, I am facing difficulties in sending JSON data: My approach involves utilizing Typescript in tandem with ...