Tips for enforcing a mandatory type with TypeScript

Creating a custom type called InputType with optional properties like this:

export type InputType = {
  configJsonUrl?: string;
  configJsObject?: DataType;
  rawData?: { [key: string]: string }; 
  action?: () => void;
};

export type DataType = {
  id: string;
  type: string;
  'product-configuration': { input: string };
};

In the InputType, at least one of the optional values (configJsonUrl, configJsObject, or rawData) should be present when using this type in a React Component as shown in the examples below.

<ComponentX configJsonUrl='./data/info.json' />);
<ComponentX configJsObject={jsObject} />);
<ComponentX rawData={adhocData} />);

How can you make one of these options mandatory?

To accomplish this without merging properties, you could define the InputType like this:

export type InputType = {
  input: string|DataType|{ [key: string]: string }
  action?: () => void;
};

However, if you want to keep separate names for each property (configJsonUrl, configJsObject, and rawData), is it possible in TypeScript? Can anyone provide guidance?

Update: In your react component, you are currently implementing it like this:

const FormGenerator = ({
  configJsonUrl,
  configJsObject,
  rawData,
}: InputType ): JSX.Element => {
  const [propForForm, setPropForForm] = useState<string>('dummy');
  const [loading, setLoading] = useState(false);

  // Further logic here

Update2: Following suggestions from others, adjust the InputType definition to:

export type InputType = {
  input: {configJsonUrl: string} | {configJsObject: DataType} | {rawData: {[key: string]: string}}
action?: () => void;
};

Alter the react component accordingly:

const FormGenerator = ({input}: InputType )
// Additional rendering logic here

How do you access configJsonUrl, configJsObject, and rawData from the input object?

Answer №1

To simplify the process, you can break down your type into three separate types, each containing a single required field. Then, combine these types to create a union type for your props:

interface InputFromUrl {
  configJsonUrl: string
}

interface InputFromObject {
  configJsObject: DataType
}

interface InputFromRawData {
  rawData: { [key: string]: string }
}

export type InputType = InputFromUrl | InputFromObject | InputFromRawData;

export type DataType = {
  id: string;
  type: string;
  'product-configuration': { input: string };
};

You can determine which key is present in a variable of type InputType by using conditional checks:

declare const props: InputType;

if ('configJsonUrl' in props) {
  props.configJsonUrl // will work here
} else if ('configJsObject' in props) {
  props.configJsObject // will work here
} else {
  props.rawData // will work here
}

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

Leverage the power of TypeScript by enabling the noImplicitAny flag when working

Currently, I am looking to activate the noImplicitAny flag in my compiler. My main issue lies with utilizing lodash/fp as there are no typings available at this moment. Due to this, the compiler is generating errors due to the absence of a definition file ...

Problem with Typescript compilation in lerna package

Presently, my project is structured with lerna/react/TS setup as shown below: . ├── lerna.json ├── package.json ├── packages │ ├── patient │ │ ├── package.json │ │ ├── src │ │ │ └── ...

How can I dynamically insert various FormGroup instances into a FormArray in Angular?

I am looking to dynamically populate the order array with multiple dishes. Each dish will be stored as a FormGroup in the form, such as pizza, salad, drink, or any other type of dish. Prior to adding any items, the form structure should resemble this: this ...

Unexpected artifacts are being introduced to the build folder by the compiler

Currently, I am following the steps outlined in this Getting Started guide to set up the installation of tsoa. According to their instructions, I have created a routes.ts folder and placed it under /build: /build /routes.ts Next, in /src/app.tsx, I mak ...

The type is lacking the property onAuxClickCapture and onAuxClick

When utilizing forwardRef from React, an unexpected type error occurs: The type '{ children: ReactNode; }' is lacking the properties specified in 'Pick<ILinkProps, "className" | "children" | "accept" | "acceptCharset" | "action" | ... 34 ...

Checking conditions sequentially in Angular

I have a unique use case that requires me to verify certain conditions. If one condition fails, I should not proceed to the next one. Instead, based on the failed condition, I need to display a dialog with a title and description explaining what went wrong ...

Inferring types in a generic function with multiple parameters

In my attempt to configure a generic with the parameter serving as the key of another object, I have found success using extends keyof when both types are provided as parameters to the function. However, I encountered an issue when the type that provides ...

Is it possible for the ionic ionViewDidEnter to differentiate between pop and setRoot operations?

I am facing an issue with my ionic 3 page where I need to refresh the data on the page only if it is entered via a navCtrl.setRoot() and not when returned to from a navCtrl.pop(). I have been using ionViewDidEnter() to identify when the page is entered, bu ...

Steps to generate an accurate file order using Typescript:

Consider the scenario with two typescript files: In File a.ts: module SomeModule { export class AClass { } } And in File b.ts: module SomeModule { export var aValue = new AClass(); } When compiling them using tsc -out out.js b.ts a.ts, there are ...

Dealing with the error: "Error in checking the expression as it has been altered"

I have a dialog form where users can add new projects. I want to prevent the save buttons from being enabled until all required fields are filled in correctly. I have an isValid() function that handles this validation and it appears to be working properly. ...

Flux Utils identified an issue stating that the Class constructor App cannot be called without the 'new' keyword

Struggling to set up a Flux Util container for this React component: class App extends React.Component<{},AppState> { constructor(props:Readonly<{}>){ super(props); } static getStores(){ return [ArticlesStore]; } static calcul ...

Exploring the integration of the mongodb-stitch library within an Angular 4 application

I have been experimenting with the MongoDB Stitch service in Angular, and so far I have successfully implemented the service. However, the only way I have managed to connect to the service is by adding the js library hosted on AWS directly into the html pa ...

Enhancing Angular input validators with updates

Working on a project with Angular 6, I have set up an input field using mat-input from the Angular Material framework and assigned it an id for FormGroup validation. However, when I initialize my TypeScript class and update the input value, the validator d ...

I prefer the value to switch to false whenever I navigate to a new route and then return to the previous route, as the sidebar remains open

click here for image details view image description here Struggling to set the value as false when revisiting this site. Need assistance! Could someone lend a hand, please? ...

When I attempt to add a todo item by clicking, the Url value is displayed as "undefined"

I am facing an issue with my household app where, upon clicking the button to navigate to the addtodo page, the URL specific to the user's house is getting lost. This results in the todolist being stored as undefined on Firebase instead of under the c ...

Handling null values in React with Typescript and GraphQL: best practices

Dealing with nullable fields in GraphQL queries can be tricky. When working with a large nested query, handling all the null values cleanly becomes a challenge... For example, consider the following GraphQL query: query { markdown { authors { ...

Images in the Ionic app are failing to display certain asset files

Currently, I am working on an Ionic 4 app for both Android and iOS platforms. The issue I am facing is that only SVG format images are displaying in the slide menu, even though I have images in both SVG and PNG formats. public appPages = [ { ...

Is it necessary to create a unit test for a basic operation involving RxJS?

Imagine a straightforward class that triggers a new event to an RxJS subject whenever the window is resized. Disregard any perceived complexities, as the main point is that this class generates an event. export class ResizeService { priv ...

Is there a way to expand the return type of a parent class's methods using an object

Currently, I am enhancing a class by adding a serialize method. My goal is for this new method to perform the same functionality as its parent class but with some additional keys added. export declare class Parent { serialize(): { x: number; ...

Additional optional class name within a TypeScript component

I am utilizing class names to apply multiple classes to a React component. Within my button, I want the option to include a class to the component if desired, but it should be optional. Unfortunately, I encountered a type error as depicted in the image li ...