Advanced automatic type inference for object literals in TypeScript

When working with TypeScript, I often declare generic functions using the syntax:

const fn: <T>(arg: T)=>Partial<T>

While TypeScript can sometimes infer the type parameter of a function based on its parameters, I find myself wondering if there is a similar way to define a generic object literal that can have its type parameter dynamically inferred from its contents. Would something like this be possible?

interface XYZ { 
  obj: <T>{ arr: T[], dict: Partial<T> }
}

I am aware that I could make the entire interface generic as shown below:

interface XYZ<T> {
  arr: T[],
  dict: Partial<T>
}

However, I want to avoid this approach because it would require me to explicitly declare the generic type every time I use the interface. For instance,

const x: XYZ

would not work. If I want to keep the declaration general, I am forced to write:

const x: XYZ<any>

Unfortunately, this method does not allow TypeScript to dynamically infer the specific generic type based on the actual contents of x.

Answer №1

Hey there, if you're looking for generic values as mentioned in the discussions at Microsoft/TypeScript#17574, you'll find that they aren't readily available in the language except for generic functions. If you feel strongly about this, consider showing your support by liking the issue or sharing your specific use case.

To work around this limitation with a generic interface like:

interface XYZ<T> {
  arr: T[],
  dict: Partial<T>
}

You can create a generic function to validate a value as being of type XYZ<T> for any T, and let type inference determine T as needed. Avoid directly declaring something as type XYZ. Here's an example of how you could approach it:

const asXYZ = <T>(xyz: XYZ<T>) => xyz;

const x = asXYZ({
  arr: [{ a: 1, b: 2 }, { a: 3, b: 4 }],
  dict: { a: 1300 }
}); // results in XYZ<{a: number, b: number}>

This method is often effective in practice as it aligns well with TypeScript conventions. However, it may not fully represent the concept of "I don't care what type T is."


If you're keen on defining an existential type, although TypeScript doesn't directly support these types, you can simulate it as follows:

interface SomeXYZ {
  <R>(processXYZ: <T>(x: XYZ<T>) => R): R
}
const asSomeXYZ = <T>(xyz: XYZ<T>): SomeXYZ => 
  <R>(processXYZ: <T>(x: XYZ<T>) => R) => processXYZ(xyz);

The SomeXYZ type essentially disregards the specifics of T and holds a reference to XYZ<T> for an undetermined T. With asSomeXYZ, you can create an object of this type:

const someXYZ: SomeXYZ = asSomeXYZ({
  arr: [{ a: 1, b: 2 }, { a: 3, b: 4 }],
  dict: { a: 1300 }
}); // Returns SomeXYZ

To utilize it, provide a function that processes the referenced value. This function must handle XYZ<T> for any possible T:

// Usage example
const xyzArrLength = someXYZ((xyz => xyz.arr.length))

In this scenario, xyzArrLength will be a number since the function always returns a number regardless of the actual T.

While existential types in TypeScript can be cumbersome due to their control flow implications, the workaround I initially shared is often simpler to implement and understand despite its limitations.

Hoping this information proves useful for your needs. Best of luck!

EDIT: Upon revisiting your question, it seems you might actually benefit from the "workaround" solution I suggested earlier. Feel free to give it a try! Cheers.

Answer №2

interface OurGenericObjectLiteral<T> {
  items: T[],
  properties: Partial<T>
}

interface ABC { 
    data: OurGenericObjectLiteral<any>
}

The ABC interface shown above will not be generic overall, only the subobject OurGenericObjectLiteral will be. It aligns closely with your original requirements, although the syntax may vary slightly.

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

Instruction failed to produce HTML output

Currently facing a challenge with my code - I have a dynamically created span (via ng-repeat). <span my-size id="abc"></span> <span my-size id="def"></span> <span my-size id="ghi"></span> The goal is to extract the id ...

I am searching for a straightforward Rails sample that incorporates Ajax

Currently, I am on a quest to find a solid demonstration of how AJAX and JSON interact with Rails. I have a Rails application that relies on standard forms and I am looking to enhance it with some ajax functionality. Unfortunately, I haven't come acro ...

Personalized AngularJS required text

After utilizing the built-in AngularJS directive required and encountering a validation error, I receive a small popup near the field displaying "Please fill out this field". My issue lies in needing the text to be displayed in another language. How should ...

Animate the entire paragraph with CSS hover effect

I'm seeking ideas on how to achieve a specific effect without the need to wrap individual lines in inner elements like span or a. Check out this example <div class="m-linkitem"> <h1>Hover Below</h1> <a href="#">Lorem ...

store user settings in local storage

After writing some code with a link that toggles text visibility upon click, I now want to incorporate saving this state in web storage so that it persists upon page reload. As a beginner in JavaScript and HTML, this task has proven challenging for me. Th ...

Using words instead of symbols to represent logical operators

When coding in C++, I typically prefer using the 'word' operators: not instead of ! and instead of && or instead of || I find it easier to read, especially when negating statements with not. Is there a similar approach possible in ...

Identifying text within clicked divs using identical ids

$(document).ready(function(){ $('#peoplelayer').click(function(){ $(this).fadeOut(500); var str = $(this).text(); alert(str); }); }); This is code where I use the same id "#peoplelayer" for all the divs. When on ...

Using Bootstrap, jQuery, and PHP to dynamically load input fields in a modal window

I am looking to dynamically load input fields in a modal window using PHP. While researching, I came across suggestions to utilize AJAX for this purpose. However, I have limited knowledge about AJAX. The plan is as follows: 1) When the user clicks on the ...

Optionalize keys containing a specific character in their name

Imagine I have an object similar to the following: const obj = { a: 1, "b?": 2, "c?": 3 } The current type of this object is as follows: type Obj = { a: number; "b?": number; "c?": number; } Is there a ...

Cease the ongoing Ajax request and switch to a new Ajax call immediately

Within this code snippet, I am capturing user input for typing and then searching it in a database. However, with each character entered by the user, a new AJAX request is triggered without canceling the previous one. My objective is to have the search fu ...

Is it possible that the images are unable to load on the page

The frontend code successfully retrieves the image links sent by the backend but encounters issues displaying them. Despite confirming that the imgUrl data is successfully fetched without any hotlink protection problems, the images are still not appearing ...

Creating a unique WooCommerce product category dropdown shortcode for your website

I am having trouble implementing a WooCommerce categories dropdown shortcode. Although I can see the drop-down menu, selecting a category does not seem to trigger any action. Shortcode: [product_categories_dropdown orderby="title" count="0" hierarchical=" ...

Most effective method to verify if mutation observer meets specific criteria

I have set up a mutation observer to monitor changes in the page load. Specifically, I am interested in detecting the moment when a particular element is loaded or exists. This element can be identified by its classname, let's say it's called foo ...

What could be the reason for certain Angular modules importing successfully while others fail to do so?

I am encountering an issue with a module that I am struggling to import. Using Typescript 2.7 and Node 10 The pxl-ng-security module is showing an error in both VSCode and VS2019. When hovering over it, error 2307 is displayed. Below is the import secti ...

Position the buttons in the react children's application

**Looking for help on positioning Black Widow in the center-left and Hulk at the bottom left of the screen. I'm having trouble figuring it out, does anyone have any tips? Also, I only want to isolate the buttons to each picture. Not sure if I need to ...

Transferring event arguments to JavaScript in ASP.NET C# through OnClientClick

Currently, I have an asp button on my webpage. In the code behind within the Page_Load method, I am assigning some JavaScript calls in the following manner. btnExample.OnClientClicking = "functionOne(1,2);"+"function2()"; However, I am encountering a pro ...

Utilizing React Native Camera Kit allows for the seamless and continuous scanning of QR codes, offering multiple callbacks when a code is

Attempting to integrate a QR code scanner into my project using react native. Utilizing the plugin react-native-camera-kit, which supports both QR and Bar code scanning. However, I am facing an issue where the scanner continuously scans the code and trig ...

Retrieving a list of actions triggered: Redux

In my Angular project, I am utilizing Redux to manage state and handle API calls. While exploring the redux devtools, I discovered a comprehensive list of executed actions. Is there a method to access a similar list of actions triggered within my angular a ...

Using JavaScript to Filter Arrays with Partial String Matching

I have an array of objects where the value I need to filter on is nested in a lengthy string. The array is structured as follows: { "data": { "value": & ...

Is there a more efficient method than creating a separate variable for the navbar on each individual page where it is being utilized?

Apologies for the unclear title, I struggled to find the right wording and decided it would be easier to illustrate with code. Let's assume I have the following routes: router.get('/chest', (req, res)=>res.render('muscles/chest/chest ...