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

Implementing pagination within an Angular 11 Mat-table with grouping feature

Encountering an interesting issue with MatTable pagination and grouping simultaneously. I have two components each with a Mat-table featuring Pagination+Grouping. ComponentOne functions smoothly without any issues. When choosing to display 5 elements pe ...

Generating Tree Structure Object Automatically from Collection using Keys

I am looking to automatically generate a complex Tree structure from a set of objects, with the levels of the tree determined by a list of keys. For example, my collection could consist of items like [{a_id: '1', a_name: '1-name', b_id ...

Angular Appreciation Meter

Looking to create a rating system using Angular. The square should turn green if there are more likes than dislikes, and red vice versa (check out the stackblitz link for reference). Check it out here: View demo I've tried debugging my code with con ...

Incorporating HTML code within a .ts file: a basic guide

I'm relatively new to Angular, but I've been given a project that's built with Angular. As I examine the .ts file containing the list of property types, I need to wrap a span around the label text. Is this doable? Here is the current list ...

There was an error during compilation: Module not detected - Unable to locate './xxxx'

Looking for help with importing a file from another folder into my Next.js project. I need assistance with the correct syntax and paths as I am encountering an error. Here is a link to the screenshot of the error: Below are the two files: //src/component ...

Exploring methods to retrieve the status attribute of an Angular httpClient response

Here is the code snippet that I am working with: this.http.post(url, payload) .subscribe( (req:any)=>{ if(req.status != 200){ console.log('non 200 status'); The this.http in my code refers to a service tha ...

Exploring the capabilities of google-diff-match-patch within the Angular framework

Seeking a way to incorporate the google diff/match/patch lib into an Angular application for displaying the variance between two texts. Here's how I plan on using it: public ContentHtml: SafeHtml; compare(text1: string, text2: string):void { var ...

Issue with exclude not functioning in tsconfig.json for Angular Typescript deployment

I am encountering an issue with a module within the node_modules directory while compiling my Angular 4 project. The error messages I'm receiving are as follows, even after attempting to exclude the problematic module in the tsconfig.json file. Can an ...

Creating a Typescript interface for a sophisticated response fetched from a REST API

I'm currently struggling with how to manage the response from VSTS API in typescript. Is there a way to handle this interface effectively? export interface Fields { 'System.AreaPath': any; 'System.TeamProject': string; 'Sys ...

Working with dual generic parameters in a function

Here is a function I am using: bind<T, K extends keyof T>( data: T[], bindedData: T[], key: K, newKey: string ) { } I'm trying to use two generic parameters, but my attempt here did not work: bind<T, K extends keyof T> ...

Expressjs makes it easy to upload audio files to your website

Currently, I'm developing a music app and I'm looking for the best way to upload an audio file in my ExpressJS application. Is it possible to use Cloudinary or is there another method that is more efficient? I attempted to follow the same proces ...

Express throwing module errors

I encountered an issue while attempting to expose a REST service in an electron app using expressJS. Following a tutorial, I added express and @types/express to the project. However, when trying to implement a "get" method and running the build with ng bui ...

"Angular 2: Organize and refine data with sorting and

Sorting and filtering data in Angularjs 1 can be done using the following syntax: <ul ng-repeat="friend in friends | filter:query | orderBy: 'name' "> <li>{{friend.name}}</li> </ul> I have not been able to find any ex ...

Vitest encountered an issue fetching a local file

I am currently working on testing the retrieval of a local file. Within my project, there exists a YAML configuration file. During production, the filename may be altered as it is received via a web socket. The code functions properly in production, but ...

tsc will automatically incorporate additional files

I'm grappling with a frustrating issue related to tsc that's really getting to me. The problem involves having a file b.ts in the src folder, and another file a.ts in the project root folder. Here is an excerpt of my tsconfig file: { "comp ...

Ways to conceal a table and button in the absence of data for display

I've been working on a way to hide the table and the 'changeState' button when there's no data present. Currently, I have set it up so that a message saying 'No entries in the list!' pops up briefly before disappearing, bringi ...

Integrating Constant Contact API into a Next.js application

I'm trying to integrate the Constant Contact API into my Next.js application. I've looked through the documentation, but it only provides examples for PHP and Java. How can I effectively use the authentication flow and create an app on the dashbo ...

I'm having trouble grasping the concept of 'globals' in TypeScript/NodeJS and distinguishing their differences. Can someone explain it to me?

As I review this code snippet: import { MongoMemoryServer } from "mongodb-memory-server"; import mongoose from "mongoose"; import request from "supertest"; import { app } from "../app"; declare global { function s ...

The debugger extension for Visual Studio Code in Chrome, [webkit-debug-adapter], received a response from the target application, but was unable to find any valid target

I am currently working on an Angular/TypeScript application and have been able to debug the TypeScript code in Chrome thanks to the map files. Recently, I decided to install the Debugger for Chrome extension from Visual Studio Marketplace. You can find it ...

Failed to decipher an ID token from firebase

I'm feeling extremely frustrated and in need of assistance. My goal is to authenticate a user using Google authentication so they can log in or sign up. Everything worked perfectly during development on localhost, but once I hosted my app, it stopped ...