TypeScript interface with an optional parameter that is treated as a required parameter

Within my interface, I have a property that can be optional. In the constructor, I set default values for this property, which are then overridden by values passed in as the first parameter. If no properties are set, the defaults are used.

I am looking for a way to keep the parameter optional when passed into the constructor but ensure that it is considered as set within the class. I want to avoid receiving the error:

Object is possibly 'undefined'.

TypeScript Playground

export interface IMain {
  req: string;
  prop?: ISecondary;
}

export interface ISecondary {
  a?: string;
  b?: string;
}
export class ABC {
  public main: Main;

  public constructor(main: Main) {
    this.main.prop = {
      a: "A",
      b: "B",
      ...main.prop
    };
  }

  public doSomething() {
    this.main.prop.a = "Z";
  }
}

new ABC({
  req: 'cat'
});

Answer №1

To designate a property as required for the class and update the constructor accordingly, you can modify it like this:

export class ABC {
    public main: Required<IMain>;

    public constructor(main: IMain) {
        this.main = {
            ...main,
            prop: {
                a: "A",
                b: "B",
                ...main.prop
        }};
    }
}

If there are properties that need to remain optional, you must specify your types more explicitly. For example:

type OptionalProps<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>

export interface IMain {
    req: string;
    prop: ISecondary; // Make it required here
}

export class ABC {
    public main: IMain;

    public constructor(main: OptionalProps<IMain, 'prop'>) {
        this.main = {
            ...main,
            prop: {
                a: "A",
                b: "B",
                ...main.prop
        }};
    }
}

If things get too complex, consider defining separate interfaces or extracting common properties to a parent interface. For instance:

interface IMainRequired {
    req: string;
}
interface IMainOptional {
    prop: ISecondary;
}
export type IMain = IMainRequired & IMainOptional
export type IMainArg = IMainRequired & Partial<IMainOptional>

export class ABC {
    public main: IMain;

    public constructor(main: IMainArg) {
        this.main = {
            ...main,
            prop: {
                a: "A",
                b: "B",
                ...main.prop
        }};
    }
}

Answer №2

To ensure that all properties are optional, one method is to define the property as non-optional and then utilize a Partial<IMain> to make all arguments optional:

export interface IMain {
  prop: ISecondary;
}

export interface ISecondary {
  a?: string;
  b?: string;
}

const ISecondaryDefaults: ISecondary = {
  a: "A",
  b: "B",
};

export class ABC {
  public main: IMain;

  public constructor(main: Partial<IMain>) {
    this.main = {
      ...main,
      prop: {
        ...ISecondaryDefaults,
        ...main.prop,
      },
    };
  }

  public doSomething() {
    this.main.prop.a = "Z";
  }
}

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

What is the proper location to insert CSS within Laravel?

What is the recommended location for storing CSS or JS files in Laravel? More specifically, what are the differences between placing CSS files in /public versus /resources/css? Which directory is preferable for storing my CSS files? ...

Unreliable static URLs with Next.js static site generation

I've recently built a Next.js website with the following structure: - pages - articles - [slug].js - index.js - components - nav.js Within nav.js, I have set up routing for all links using next/link, including in pages/articles/[slug].j ...

Tips for splitting JSON objects into individual arrays in React

I'm currently tackling a project that requires me to extract 2 JSON objects into separate arrays for use within the application. I want this process to be dynamic, as there may be varying numbers of objects inside the JSON array in the future - potent ...

What is the method used by React or Next to prevent the <a> tag from refreshing the page while still loading content?

I'm currently diving into the world of NextJS and utilizing the Link component from the 'next/link' package. One thing that has been puzzling me is how the <Link> component ultimately renders an <a> tag with a href='/tosomew ...

Generating intricate JSON structures with JavaScript programming instructions

In the world of JSON, I am still a novice. I need to use JavaScript to construct the JSON structure below, but I'm struggling with adding the second element ("12101") and populating the people in the JSON Structure. Below is the code I tried, however, ...

Using a JavaScript array in Java

Currently, I am working on an Android app that requires me to download data from a JavaScript array representing the schedule for my school. The link to the data is here. I am looking for a way to parse this data into a Java array. I have considered using ...

The DataType.MultilineText field in my modal popup partial view is causing all validation to fail

I encountered a peculiar issue recently. After creating a new asp.net mvc5 application, I decided to upgrade it to asp.net mvc-5.2.2. The problem arose with the following field:- [Required] [StringLength(200)] public string Name { get; set; } When ren ...

What are some ways to execute a script prior to installing an npm package?

I need help creating a test for npm packages in my project. I want to ensure that every time I attempt to install a module using npm install <module>, a script runs before the module is installed. However, I've noticed that the preinstall script ...

Setting the paths property in a project with multiple tsconfig.json files: a step-by-step guide

My file structure is organized as follows: |__ app1/ | |__ tsconfig.json |__ utilities/ | |__ files.ts |__ base-tsconfig.json I have defined the paths property in base-tsconfig.json like this: "compilerOptions": { "baseUrl": ".", "pa ...

The module 'angular/common' was not found in the Angular 2 TypeScript

While experimenting with a sample login form in Angular 2, I encountered an issue when trying to import 'Form_Directives' as: import { FORM_DIRECTIVES } from '@angular/common'; An error was displayed stating that the angular/common m ...

An element in CSS that has a position of fixed and a width of 100% surpasses the dimensions of its

My element has the CSS properties position:fixed and width:100%, causing it to be larger than its parent elements. Despite the complexity of my code, I have attempted to simplify it for better understanding. Below, you can see that the green box exceeds ...

Tips for sorting through existing data without resorting to a remote call - Material Table repository by mbrn (mbrn/material

Currently I am using the mbrn/material-table library which includes filtering on a column and remote data feature. However, when I apply a filter term, the table sends an API call to the server with the filter criteria in the query object. My desired outco ...

Locate the highest and lowest values within a .json file

When working on a graph using d3.js, one key step is setting up the scales for the axis. The data for the graph is stored in a Json file with multiple arrays, each representing different regions and years: [{ "id" : "AustraliaNewZealand" , "year" ...

What is causing the object, which is clearly defined (as shown in the callback to JSONLoader), to be interpreted as undefined

Why is the THREE.Mesh() object showing as undefined even though it was defined in a THREE.JSONLoader()? Here is the code snippet... 1: var player; 2: var playerCallback = function(geo, mats){ 3: player = new THREE.Mesh(geo, new THREE.MeshFaceMaterial( ...

Angular JS allows for the display of text from a textarea upon clicking the submit button

Q] How can I display a single text message from a textarea upon clicking the submit button in angular-js? Here is the current code that I have: <html ng-app="myApp"> <head> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1 ...

Create a dynamic animation effect by making a div slide on and off the screen

I'm having trouble figuring out how to make my div slide with a toggle button. I attempted to use variables, but since I have multiple instances of this, it's becoming too complicated to keep track of all the clicks on each one. $(document).r ...

Tips for extracting text from a textarea while retaining newline characters:

When using jquery, my goal is to retrieve the text from a textarea element with new lines represented as \n instead of br tags. However, I encountered an issue where Firefox debugger does not display the \n or br characters when I select it and r ...

The module 'iap_verifier' could not be located

Setting up a new server using the following repository - https://github.com/surespot/web-server. I have successfully installed node.js, npm, CoffeScript, and all required dependencies. apt-get install nodejs npm npm install -g <a href="/cdn-cgi/l/email ...

identifying the element targeted on dynamically created links with the help of jquery

I have created dynamic links where clicking on a country link displays the cities of that particular country. I am trying to retrieve the event.target.id of the dynamically generated city link when it is clicked. $(".countryName").children().on('cl ...

Showing formatted JSON (Large Object) on an HTML page

Having trouble displaying formatted JSON in an HTML page, especially when dealing with larger objects (an array of objects). The current method involves using JSON.stringify(data) to display the JSON object upon receiving a response from the server. The P ...