Ways to improve the feedback for Typescript when dealing with the potential existence of a nested method

Recently encountered a critical bug that I believe could have been identified with the right TypeScript setup. Struggling to come up with a suitable title, so please bear with me.

While initializing a widget app, similar to a chat app loaded by a parent app, we implement something like this:

type TParamsRoot = {
  print: () => void;
}
type TParams = {
  root?: TParamsRoot;
}

const init = (params: TParams = {}) => {
  params.root ??= {
    print: () => console.log('hello')
  }
}

The concept here is that the parent app should pass on params when loading the widget app, but in case it doesn't, a default value is assigned.

At some point in the code, I call params.root.print as shown below:

const printConfig = () => {
    params.root.print()
}

The initial issue was that TypeScript didn't warn me about params.root possibly being undefined. I addressed this by enabling strict mode in my tsconfig and modifying the function to:

const printConfig = () => {
    params.root?.print()
}

However, this wasn't enough because there was no error notification, leading to a bug. Even though I'm checking for params.root?, I am still calling

print</code. To resolve this bug, I need to do:</p>
<pre><code>const printConfig = () => {
    params.root?.print?.()
}

But how can I prompt TypeScript to alert me that print might not be a function or even undefined? While init guarantees it will always exist, I use this logic in a hook that is utilized in a component rendered before init is triggered by the parent app, hence causing the bug.

Is my sole solution to define,

type TParamsRoot = {
  print?: () => void;
}

It seems slightly misleading because if params.root exists, then params.root.print will also invariably exist.


In regard to the short-circuiting issue:

const params = {
    root:
        
}

params.root?.print()

The above is what I relied on - indeed, it does short circuit. However, I have discovered that even when root is passed, it may not always include print. Problem resolved.

End of query.

Answer №1

There is no need to check for undefined on the variable print because it will always be present if the condition params.root is not undefined, just as you mentioned.

The value of print cannot be undefined.

The error related to undefined was due to the absence of value in params.root. Your solution has effectively addressed this issue.

Answer №2

Another option to consider is:

const displayConfiguration = () => {
    if (typeof parameters.base?.show === 'function') {
        parameters.base.display();
    }
}

This method not only verifies the existence of parameters.base but also confirms that show is a function before calling it.

If you are confident that a value will always be non-null or defined after a certain stage, you can utilize the non-null assertion operator !

parameters.base!.display!();

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

Exploring Angular 9: Experimenting with iterating over a collection of objects and performing validations

Forgive me if this is a basic question, but I am new to Angular 9 and json. I am attempting to iterate through a list and only create a table row if the correct ID matches the ID passed from the previous page link. I am struggling to make the if statement ...

What steps can I take to perform unit testing on a custom element?

While working on a project where I have a class that extends HTMLElement, I came across some interesting information in this discussion: https://github.com/Microsoft/TypeScript/issues/574#issuecomment-231683089 I discovered that I was unable to create an ...

Click on the button to open the generated link in a new tab

How can I efficiently open a URL in a new tab after making an API call with the click of a button? Currently, the button triggers the API call and generates the URL. <button (click)="getUrl()">Connect</button> In TypeScript: getUrl() ...

What are the steps to globalize the ng-bootstrap datepicker?

For my current project, I am utilizing the ng-bootstrap datePicker component. The demo for my simple datePicker widget can be found here. However, I am now seeking to internationalize it by setting it to use the Russian language. Any assistance with this ...

TypeScript is unaware that a component receives a necessary prop from a Higher Order Component (HOC)

My component export is wrapped with a higher-order component (HOC) that adds a required prop to it, but TypeScript seems unaware that this prop has already been added by the HOC. Here's the Component: import * as React from "react"; import { withTex ...

Issue: MUI Autocomplete and react-hook-form failing to show the chosen option when using retrieved information

The MUI Autocomplete within a form built using react hook form is causing an issue. While filling out the form, everything works as expected. However, when trying to display the form with pre-fetched data, the Autocomplete only shows the selected option af ...

Expressjs - Error: Headers already sent to the client and cannot be set

After testing various solutions from others, I am still unable to resolve this error. My objective is to iterate through each item in the array sourced below: novel.ts export let indexList = (req: Request, res: Response) => { novel.getAllDocuments ...

How can we implement `injectReducer` in Redux with TypeScript?

I have been working on a TypeScript React application with Redux to manage state. To dynamically add reducers, Redux suggested implementing an injectReducer function. In a JavaScript project, I successfully implemented this function. However, I am strugg ...

Enhancing JavaScript with TypeScript: implementing functional mixins

I'm in the process of creating functional mixins using TypeScript. Below is the code I have written so far: const flying = (o: object) => { let isFlying = false; return Object.assign({}, o, { fly() { isFlying = true; return thi ...

Angular5+ Error: Unable to retrieve summary for RouterOutlet directive due to illegal state

When attempting to build my Angular App using ng build --prod --aot, I consistently encounter the following error: ERROR in : Illegal state: Could not load the summary for directive RouterOutlet in C:/Path-To-Project/node_modules/@angular/Router/router.d. ...

Error encountered: Unable to locate module 'psl'

I'm encountering an issue when trying to execute a pre-existing project. The error message I keep receiving can be viewed in the following error logs image Whenever I attempt to run "npm i", this error arises and I would greatly appreciate it if some ...

Converting a JSON array into a TypeScript array

Looking to convert a JSON array into a TypeScript variable array. The JSON data retrieved from http://www.example.com/select.php: { "User":[ {"Name":"Luca M","ID":"1"}, {"Name":"Tim S","ID":"2"}, {"Name":"Lucas W","ID":"3"} ...

Mapping JSON to interface in Angular 7: A step-by-step guide

I am currently working with angular7 and I have a requirement to map a json object to my interface. My goal is to create a function that can accurately map the fields of the json object to the corresponding properties in the interface. Additionally, if the ...

Determine whether an element is visible following a state update using React Testing Library in a Next.js application

I'm looking to test a NextJS component of mine, specifically a searchbar that includes a div which should only display if the "search" state is not empty. const SearchBar = () => { const [search, setSearch] = useState(""); const handleSear ...

Tips for preventing the need to cast a DOM element to any in Typescript

In my Typescript code, I am retrieving the value of a DOM element like this: document.getElementById('MyElementId') as HTMLElement).value I feel unsure about casting it to HTMLElement. Is there a better way to specify the type and retrieve this ...

How do I fix the build error that says "Operator '+' cannot be used with types 'number[]'?

The function below is designed to generate unique uuidv4 strings. function uuidv4() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => ( c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)) ...

Exploring Angular routing with parameters and extracting parameter values

In an email, a user will click on a link that looks like this: do-something/doSomething?thing=XXXXXXXXXXX I'm trying to figure out how to define the route in the router and subscribe to get params. Here's what I currently have set up in the rout ...

How can the outcome of the useQuery be integrated with the defaultValues in the useForm function?

Hey there amazing developers! I need some help with a query. When using useQuery, the imported values can be undefined which makes it tricky to apply them as defaultValues. Does anyone have a good solution for this? Maybe something like this would work. ...

The slice() method in arrays provides a reference to the elements rather than copying

In my file, I am exporting an object in the following manner: export const LINECHART2_DATA = { series: [{ data: [], name: 'HR', }, { etc... }] } The way I import it is like this: import { LINECHART2_DAT ...

Tips on inferring a distinct generic type for every element within an array of objects

I'm working on code that creates a timeline chart for data. I want the code to accept an array of series, each containing data and various getters used to position and render the data on the chart. Below is a simplified example of the code. The actua ...