Is it possible to create a return type structure in TypeScript that is determined by the function's argument?

I'm currently stuck on developing a function that takes a string as an argument and outputs an object with this string as a key.

For example (using pseudo code): test('bar') => {bar: ...}

I am facing difficulties in ensuring the correct return type for this function.

While the following code provides me with the desired return type, the TypeScript compiler is still unable to recognize that my returned object matches the specified return Type:

function test<K extends string>(key: K):{[prop in K]: number} {
  return { [key]: 6 } // error: not assignable
}
const foo = test<'bar'>('bar')
// foo type: {bar: number} // return type is good

The above approach works well, but unfortunately does not give me the strongly typed return type I am aiming for. Instead, something like this would work fine:

function test2<K extends string>(key: K){
  return { [key]: 6 }
}
const foo2 = test2<'bar'>('bar')
// foo2 type: {[x: string]: number}  // no good

Any assistance on this matter would be greatly appreciated!

Answer №1

After making some adjustments to the initial solution, it appears to be functioning correctly:

function generateKey<T extends string>(key: T) {
  return { [key]: 6 } as {[property in T]: number}
}

const result = generateKey('example') // { example: number }

The need to use type casting still strikes me as odd.

Answer №2

There are endless possibilities with extended typings.

As demonstrated by @SnailCrusher, you can statically define the return type. Furthermore, there is a method to dynamically allocate typings to the returned properties:

// The interface below specifies potential parameters for the methods

interface Tokens {
    foo: number,
    bar: string,
}

// Return one property in the resulting object
// These methods only accept keys from the Tokens interface as valid inputs

function test<K extends keyof Tokens>(key: K) {
    switch(key) {
        case 'foo': return { [key]: 0 } as {[prop in K]: Tokens[K]}
        case 'bar': return { [key]: '0' } as {[prop in K]: Tokens[K]};
    }
    return { [key]: undefined } as {[prop in K]: Tokens[K]}
}

const bar = test('bar') // { bar: string }
const foo = test('foo') // { foo: number }

// Return the entire interface in the result object
// The specified token will be included and all other properties will be optional

function test2<K extends keyof Tokens>(key: K) {
    return { [key]: 6 } as {[prop in K]: Tokens[K]} & {[P in keyof Tokens]?: Tokens[P];}
}

const bar2 = test2('bar') // { foo?: number; bar: string; }
const foo2 = test2('foo') // { foo: number; bar?: string; }

This will also provide comprehensive context in your IDE regarding valid parameters.

You can explore more of this in the Typescript documentation: https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types-and-index-signatures

Answer №3

I am puzzled as to why generics are necessary in this situation. Isn't it simpler to just use the following code snippet?

function test(key: string): { [key: string]: number } {
  return { [key]: 6 };
}

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

Even with the text field populated and clearly existing, Firefox is still throwing a null error when trying to retrieve it using

Hey there! I'm currently working on a sample HTML page and I'm facing an issue with retrieving data from a text field. No matter what I try, I keep encountering the following error: TypeError: document.getElementById(...) is null Let me share t ...

Saving any type of file in SQL Server with a field type of varbinary(max) can be achieved by utilizing Angular with ASP.NET Core to create a REST API

I am currently facing an issue while attempting to save a file, such as an image, in the Microsoft SQL Server Management Studio through asp .NET core for the Rest API. I have managed to create a base64 representation of the file, but I am unsure about the ...

Typescript controller inheritance leading to Error: $injector:unpr Unknown Provider due to minification

LATEST UPDATE: 2019/07/16 The issue I am facing is actually a result of misusing $inject. Instead of declaring it as private $inject in api-service.ts, it should have been public static $inject = [...]. During the minification process, explicit injection ...

Initiate the python script on the client's end

Currently, I am in the process of initiating a Python script designed to parse a CSV file that has been uploaded by the user through the UI. On the client side, how can I effectively trigger the Python script (I have explored using AJAX HTTP requests)? Add ...

extracting key-value pairs from nested arrays in javascript objects

As a beginner in javascript, I am facing an issue that may seem basic to others. Here is the json data I am working with: { "statusCode": 200, "status": "success", "data": [ [ { "city": "Alexandria", ...

Sending a Form Generated in Real Time with a Button Located Outside the Form

I'm currently working on a feature that allows users to add multiple invoices on a single page. Users can click on a link to display the invoice fields in a modal form, which is dynamically generated using AJAX. Once the user has filled out the requi ...

`Unable to upload spreadsheet file in xlsx format`

I'm currently working on implementing a feature to export data as xlsx files. I have been successful in exporting CSV and PDF formats, but encountered issues with the xlsx format due to dynamic imports. export const exportToXlsx = async ( gridElemen ...

Unexpected date outcomes in JavaScript when using a similar date format

Why is it that the first input produces the correct result, while the second input displays a time that is 5 hours behind? new Date("2000-1-1") Sat Jan 01 2000 00:00:00 GMT-0500 (EST) new Date("2000-01-01") Fri Dec 31 1999 19:00:00 GMT-0500 (EST) How can ...

jquery disable document manipulation function

I need to make some updates to a simple function that involves the current textarea. $(document).on("keydown", updated_textarea_var, function (e) { // do stuff }); To achieve this, I tried disabling the previous function and running a new one w ...

Troubleshooting data binding issues in Angular.js using Jade and Express

I've been diving into AngularJS using Dan Wahlin's tutorial (http://youtu.be/i9MHigUZKEM?t=13m35s). In my views/index.jade file, I've implemented the code below: !!! 5 html(data-ng-app='') head title Angular Tutorial body ...

I have encountered an issue where after declaring a JavaScript variable on a specific page, including the JavaScript file does not grant access to it

<script type="text/javascript"> $(document).ready(function () { var SOME_ID= 234; }); </script> <script type="text/javascript" src="<%= HtmlExtension.ScriptFile("~/somefile.js") %>"></script> ...

Finding the Number of Days Between Two Dates in AngularJS Using JavaScript

When I receive two dates from a web service in the format below: var dateone = "2016-08-21T07:00:00.000Z"; var datetwo = "2016-08-28T07:00:00.000Z"; var datediff = datetwo - dateone; var numdays = Math.round(datediff); console.log("Number of Days is " + n ...

Issue with Angular 7 service worker caching audio files leads to range header problems in Safari browser

I am encountering an issue in my Angular application with the range request header for audio files when using Safari. When requesting audio from a server, the duration of the audio file is returned correctly. However, when requesting the audio from the ser ...

The state update is triggering a soft refresh of the page within Next.js

In my Next.js project, I have integrated a modal component using Radix UI that includes two-way bound inputs with state management. The issue arises when any state is updated, triggering a page-wide re-render and refreshing all states. Here is a snippet of ...

Hmm, JavaScript is throwing a JSON parse error related to single quotes. But where exactly is

When using an upload php script with AS3 and now with JavaScript, I encountered a test feature that should return this if everything is okay: {"erro":"OK","msg":"","descr":"op:ini,urlArq:\/Library\/WebServer\/Documents\/www\/sintr ...

Vue.js - when it comes to rounding off digits, I keep getting unexpected results

Currently, I am in the process of calculating my totals and I need to ensure that they are fixed to 2 decimal places. Here is a snippet of my code: this.selectedCompaniesDetails.forEach((company) => { if(company.id == p.compa ...

Is it more beneficial to convert all the current jQuery AJAX webparts into Typescript or should I opt to inject the existing jQuery into SPFX instead?

Transitioning from SharePoint 2013 to SharePoint online raises the question of how to migrate existing webparts that utilize jquery - ajax to SPFX client webparts. One possibility is rewriting all the code in Typescript, but is it possible to simply inje ...

Implement auto partial page refreshing in ASP.NET without using the UpdatePanel feature

Looking to implement auto partial page refresh in asp.net without sending excessive data through UpdatePanel. Considering using a webservice called by JavaScript instead, but unsure how to trigger it automatically rather than by button click event. Many e ...

Encountering the "React Hook useEffect missing dependency" warning for a state variable that does not actually need to be included in the dependency array

My eslint is throwing an error for react-hooks/exhaustive-deps. I believe my code is correct as the function should only execute when there is a change in the pathname: const pathname = usePathname(); useEffect(() => { setNavigation( navig ...

"The function you are attempting to call is not defined within the HTMLButtonElement.onclick

How do I trigger the DeleteRow and EditRow functions when clicking on the Delete Button and Edit Button? <button style="margin-right: 5px;" type='button' onclick='return EditRow(@i)' id='@editrow' class='btn btn-prima ...