What is the correct way to construct an object in TypeScript while still taking types into account?

Hey, I'm having trouble implementing a common JavaScript pattern in TypeScript without resorting to using any to ignore the types. My goal is to write a function that constructs an object based on certain conditions and returns the correct type. Here's a simplified example:

Is it feasible to make the following function work without relying on any?

function hasAB<A extends boolean, B extends boolean>(shouldHaveA: A, shouldHaveB: B): HasAB<A, B> {
    const obj: any = {}
    if (shouldHaveA) obj.a = ""
    if (shouldHaveB) obj.b = ""
    return obj
}
type HasAB<A extends boolean, B extends boolean> = 
    (A extends true ? {a: string} : {}) &
    (B extends true ? {b: string} : {}) 

const a = hasAB(true, false)
const b = hasAB(false, true)
const ab = hasAB(true, true)

The return types for a, b, and ab are accurate, but the compiler does not perform any checks on the code. For instance, you could set obj.a twice and it would go unnoticed.

// attempt 1 and 2 fails because inference takes the union of conditionals e.g. const five = true ? 5 : 4; // five: 5 | 4 function attempt1<A extends boolean, B extends boolean>(shouldHaveA: A, shouldHaveB: B): HasAB<A, B> { return { ...(shouldHaveA ? { a: "" } : {}), ...(shouldHaveB ? { b: "" } : {}) } } function attempt2<A extends boolean, B extends boolean>(shouldHaveA: A, shouldHaveB: B): HasAB<A, B> { const obj1 = shouldHaveA ? {a: ""} : {} const obj2 = shouldHaveB ? {...obj1, b: ""} : obj1 return obj2; } // attempt 3 can't get over the hurdle of needing to assign an intial type function attempt3<A extends boolean, B extends boolean>(shouldHaveA: A, shouldHaveB: B): HasAB<A, B> { let obj = {} if (shouldHaveA) { obj = { ...obj, a: "" } } if (shouldHaveB) { obj = { ...obj, b: "" } } return obj } // attempt 4 fails too function attempt4<A extends boolean, B extends boolean>(shouldHaveA: A, shouldHaveB: B): HasAB<A, B> { if (shouldHaveA) { const a = {a: ""} } if (shouldHaveB) { const b = {...(a || {}), b: ""} } const final = b || {} return final } // attempt 5 fails because ternary always assumes a union function hasAB<A extends boolean, B extends boolean>(shouldHaveA: A, shouldHaveB: B): HasAB<A, B> { const obj = {} const withA: A extends true ? {a: string} : typeof obj = shouldHaveA ? {a: ""} : obj const withB: withA & (B extends true ? {a: string} : {}) = shouldHaveB ? {...withA, b: ""} : withA return withB }

Answer №1

Currently, TypeScript does not have the capability to achieve this task. The recommended approach is to utilize available typing features for tasks like checking spelling errors in objects, even though it may not guarantee the final shape of the outcome.

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

Angular 2 repeatedly pushes elements into an array during ngDoCheck

I need assistance with updating my 'filelistArray' array. It is currently being populated with duplicate items whenever content is available in the 'this.uploadCopy.queue' array, which happens multiple times. However, I want to update ...

Tips on optimizing data processing for quicker display with ngFor

I am currently facing an issue with loading a JSON file containing 3500 data. The data appears very slowly on the view, causing the application to work sluggishly. Below is a snippet of the JSON: export class Service { private items = new Arr ...

The response error from the callback of the HTTP service in CouchDB with AngularJS lacks any meaningful data

I need help writing CouchDB TypeScript classes with AngularJS http service. My call is successful in the happy path, but I'm struggling to retrieve the status code or JSON error information from the server, which is crucial for user feedback. public ...

What are the methods used in TypeScript to implement features that are not available in JavaScript, despite TypeScript ultimately being compiled to JavaScript?

After transitioning from JavaScript to TypeScript, I discovered that TypeScript offers many features not found in JS, such as types. However, TypeScript is ultimately compiled down to JavaScript. How is it possible for a language like TypeScript to achie ...

Ways to leverage Composite API in place of Mixin or Extends functionality

Currently, I am exploring the use of Vue3 for my project. One issue I am facing is that I need to create multiple components (SFC) with similar properties. I want to define these common properties using the composite API across all components, like so: con ...

What is the process for obtaining a Component's ElementRef in order to access the BoundingClientRect of that specific Component?

I have successfully created a tooltip using Angular 5.2.0 and ngrx. The tooltip, among other things, receives an ElementRef to the target Element when the state updates, allowing me to position it absolutely: let rect = state.tooltip.target.nativeElement. ...

Limiting the Size of Highcharts Maps with maxWidth or maxHeight

My attempt to adjust the maxWidth of my world map using highcharts isn't altering its size. I have experimented with the following: responsive: { rules: [{ condition: { maxWidth: 500 }, ... As recomme ...

The type 'any' cannot be assigned to the type 'never' as a parameter

const [files, setFiles] = useState([]) const handleChange = (event: any) => { setFiles.push(event.target.files[0].name) return (<div> {files.map((file: any) => ( <p>Hello!</p> ))} </ ...

Combining Repetitive Elements in an Array

Trying to combine an array of products with the same order_id while also including all objects from a second products array. Below are some sample orders: const orders = [ { "order_details": { }, "order_id": "1", ...

Steps for configuring type definitions for an Apollo error response

Apollo's documentation explains that an error response can take the following form: { "data": { "getInt": 12, "getString": null }, "errors": [ { "message": "Failed to get s ...

A step-by-step guide on enhancing error message handling for Reactive forms in Angular

Here is a code snippet that I'm working on: public errorMessages; ngOnInit(): void { this.startErrorMessage(); } private startErrorMessage() { this.errorMessages = maxLength: this.translate.instant(' ...

Error: The function list.forEach does not exist within service.buildList [as project]

Today, I've been grappling with a challenging issue. As someone new to Typescript and Angular, I'm attempting to make a call to my backend API. However, when trying to populate an array for display, I keep encountering an error that says rawRegis ...

Using TypeScript to filter and compare two arrays based on a specific condition

Can someone help me with filtering certain attributes using another array? If a condition is met, I would like to return other attributes. Here's an example: Array1 = [{offenceCode: 'JLN14', offenceDesc:'Speeding'}] Array2 = [{id ...

Can one utilize generic parameter value within a conditional type result field in Typescript?

Trying to create a versatile function type for data transformation can be a bit tricky. When dealing with a single object, it's straightforward: export type SingleObjFunction<InputDataType, OutputDataType> = (object: InputDataType) => Outpu ...

Error encountered when an Angular expression is changed after it has already been checked in a dynamically generated component

I am encountering a problem with Angular and the CdkPortal/CdkPortalHost from @angular/cdk. I developed a service that allows me to associate a CdkPortalHost with a specified name and set its Component at any given time. This is how the service is struc ...

What could be causing this discriminated union to act differently than anticipated?

Desired Outcome When the href prop is present, TypeScript should recognize that the remaining props are suitable for either a Link or Button element. However, I am encountering an error indicating type conflicts with the button element. Type '{ chil ...

Time taken for a webpage to finish loading

Is there a way to programmatically obtain the page load time in an Angular application? Situation: On my dashboard page, various components are making multiple calls. I want to calculate the overall time it takes to load all widgets on the page. ...

Optimal approach to configuring Spring Boot and Angular for seamless communication with Facebook Marketing API

Currently, I am working on a Spring Boot backend application and incorporating the Facebook marketing SDK. For the frontend, I am utilizing Angular 10. Whenever I create a new page or campaign, my goal is to send the corresponding object back to the fronte ...

Creating multiple copies of a form div in Angular using Typescript

I'm attempting to replicate a form using Angular, but I keep getting the error message "Object is possibly 'null'". HTML: <div class="form-container"> <form class="example"> <mat-form-field> ...

What is the best method for embedding my token within my user entity?

Currently, I am working on implementing a "forgot password" feature in my application. The idea is that when a user requests to reset their password, they will receive a token via email that expires after two hours. To prevent the generation of multiple to ...