Creating a factory function in TypeScript to generate union types

I have developed a unique Factory type that allows me to create factory functions.

export type Factory<T> = (state?: Partial<T>) => T;

Within my <Avatar /> React component, I have implemented a prop with a union type to accommodate for two versions of the avatar (standalone image or clickable image). This means that the component can accept either set of props.

type AvatarOnlyProps = {
  alt: string;
  src: string;
};

type ClickableAvatarProps = {
  alt: string;
  label: string;
  onClick:
    | ((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void)
    | undefined;
  src: string;
};

export type AvatarProps = AvatarOnlyProps | ClickableAvatarProps;

My goal is to create a factory function for the avatar's props. While attempting to define it, I encountered an issue:

const createProps: Factory<AvatarProps> = ({
  alt = 'Your avatar',
  label,
  onClick,
  src: source = '/images/default-avatar.png',
} = {}) => ({ alt, label, onClick, src: source });

However, TypeScript raises an error:

Property 'label' does not exist on type 'Partial<AvatarOnlyProps> | Partial<ClickableAvatarProps>'.

This error occurs in the arguments section of the factory function.

https://i.stack.imgur.com/xvf1v.png

How can this error be resolved? Is there a way to make TypeScript understand that both onClick and label must either be provided or neither?

Answer ā„–1

After some experimentation, I found a solution that worked perfectly for my specific situation. By constructing the factor function with only the essential keys populated, I was able to meet my needs:

const generateProperties: Generator<AvatarProperties> = ({
  description = 'Your avatar',
  url: link = '/images/default-avatar.png',
  ...attributes
} = {}) => ({
  description,
  url: link,
  ...attributes,
});

Answer ā„–2

It is not possible to destructure a property from a union unless it exists in all members of the union. The properties label and onClick are not defined in the AvatarOnlyProps.

How can I make TypeScript understand that either both onClick and label will be provided in this factory function, or neither?

From the way you have explained your Factory, it does not strictly require both properties or neither. A Factory of type T takes an incomplete Partial<T> as input and returns a complete T. Since it accepts Partial<T>, it might accept a

Partial<ClickableAvatarProps>
with just label or just onClick.

Default values are only set for alt and src, not for label or onClick. Therefore, if only one of these properties is provided, only that specific property will be returned.

To accurately describe this behavior, we need more than simply a union of two possibilities. The createProps function should accept an object with all four properties, where all are optional. It should return an object with all four keys, where alt and src are always strings, but label and onClick may be undefined.

We must define the object that is returned. Here is one approach:

type AvatarProps = AvatarOnlyProps & Partial<ClickableAvatarProps>;

You can now specify createProps as Factory<AvatarProps> without encountering any issues.

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

The Type {children: Element; } is distinct and does not share any properties with type IntrinsicAttributes

I am encountering an issue in my React application where I am unable to nest components within other components. The error is occurring in both the Header component and the Search component. Specifically, I am receiving the following error in the Header co ...

Issues with manipulating state using TypeScript Discriminated Unions"Incompatibility with setState

Imagine having a unique type structure like the one shown below: export type IEntity = ({ entity: IReport setEntity: (report: IReport) => void } | { entity: ITest setEntity: (test: ITest) => void }); Both the entity and setEntity fun ...

I'm struggling to find a solution to this pesky TypeScript error that keeps popping up in the button component's styling. How can

An error related to style is appearing: <Button style = No overload matches this call. Overload 1 of 3, '(props: { href : string; } & { children?: React Node; classes?: Partial<Button Classes> | undefined; color?: "primary" | ...

Preventing data loss in an Ionic array - encountering issues with using this.array.push

When attempting to use the storage get method to fill the array storedArr = [], I encounter the error message .push is not a function: storedArr = this.storage.get('stored') ? this.storage.get('stored').then((e) => {e}) : []; The c ...

Why aren't the child elements in my React / Framer Motion animation staggered as expected?

In my finance application, I am creating a balance overview feature. To display the content, I pass props into a single <BalanceEntry> component and then map all entries onto the page. With Framer Motion, my goal is to animate each rendered <Bala ...

Make sure to implement validations prior to sending back the observable in Angular

Each time the button is clicked and if the modelform is invalid, a notification message should be returned instead of proceeding to create a user (createUser). The process should only proceed with this.accountService.create if there are no form validation ...

Oops! Property 'month' cannot be set on undefined value due to a TypeError

Despite not receiving any errors from Visual Studio Code, Iā€™m encountering an error in Chrome's console. Below is the code snippet from my interfaces.ts file: export interface Data1{ month: string; employeeName: string; date: string; employmentSta ...

Using TypeScript to Implement Content Security Policy Nonce

I encountered an issue with my TypeScript Express project while attempting to implement a CSP Nonce using Helmet. app.use(helmet.contentSecurityPolicy({ useDefaults: true, directives: { scriptSrc: ["'self'", (req, res) = ...

What is the best way to pass only the second parameter to a function in TypeScript?

Let's consider a TypeScript function as shown below: openMultipleAddFormModal(commission?: Commission, people?: People): void { // some data } To make a parameter optional, I have added the Optional Chaining operator. Now, how can I modify the code ...

Encountering an issue while trying to deploy my node.js application on Heroku

While monitoring the Heroku logs using the command heroku --tail, I encountered the following error: Error: 2022-01-25T19:10:06.153750+00:00 app[web.1]: at emitErrorCloseNT (node:internal/streams/destroy:122:3) 2022-01-25T19:10:06.157055+00:00 heroku[rout ...

Introducing an extra 'pipe' in rxjs angular may result in generating errors

Encountering an unusual issue with Angular. The following code functions correctly: this.form.valueChanges .pipe( startWith(this.form.value), pairwise(), tap(() => console.log('aa')) ...

There are two modals present on the page, however only one of them is triggered for all actions in Angular 2

I'm encountering an issue with my page where I have set up two confirmation modals - one for resetting a form and another for deleting an item. Strangely, only the reset modal is being triggered for both actions and I can't figure out why. Could ...

Ways to implement a package designed for non-framework usage in Vue

Alert This may not be the appropriate place to pose such inquiries, but I am in need of some guidance. It's more about seeking direction rather than a definitive answer as this question seems quite open-ended. Overview I've created a package th ...

Leverage context to facilitate communication between components operating at various levels of the system

I am currently working on the settings pages of my applications. Each page features a common SettingsLayout (parent component) that is displayed across all settings pages. One unique aspect of this layout is the presence of an ActionsBar, where the submit/ ...

Error encountered when attempting to export a TypeScript class from an AngularJS module

In my application using Angular and TypeScript, I have encountered a scenario where I want to inherit a class from one module into another file: generics.ts: module app.generics{ export class BaseClass{ someMethod(): void{ alert(" ...

Revamping the static method signature of a class in Typescript

One of the modules I'm using is called some-module and it defines a class like this: export declare class Some<T> { ... static create<T>(): Some<T>; map<U>(x: U): Some<U>; } export default Some In my project, I ...

Unit testing the TypeScript function with Karma, which takes NgForm as a parameter

As I work on writing unit tests for a specific method, I encounter the following code: public addCred:boolean=true; public credName:any; public addMachineCredential(credentialForm: NgForm) { this.addCred = true; this.credName = credentialForm.val ...

Challenges arise with data updating following a mutation in @tanstack/react-query

As I work on building an e-commerce website using React, I have a specific feature where users can add products to their favorites by clicking a button. Following this action, I aim to update the profile request to display the user's information along ...

Sign up for the completion event within the datetime picker feature in Ionic 2

How can I subscribe to the "done" event in Ionic2, where I want to trigger a function after selecting a date? <ion-icon class="moreicon" name="funnel"> <ion-datetime type="button" [(ngModel)]="myDate" (click)="getData()"></ion-datetime> ...

The state data is not being properly updated and is getting duplicated

While developing a loop to parse my API data, I encountered an issue where the values obtained were not being captured properly for dynamically loading corresponding components based on their characteristics. The problem arose after implementing useState() ...