Upgrading the Elvis Operator in Typescript for Angular2

Is there a TypeScript operator similar to the Elvis Operator in Angular 2? For example, when trying to access a key from an object like:

this.myForm.name.first_name

and if first_name doesn't exist, it will throw an error saying first_name of undefined.

While I can handle this error using the Ternary operator in TypeScript like this:

this.myForm.name ? this.myForm.name.first_name : ''

Sometimes keys can get too long, so my question is: does TypeScript have an operator similar to the Elvis Operator in Angular 2 that would allow me to write code like this?

this.myForm?.name?.first_name

Answer №1

In the latest update of December 2019, TypeScript 3.7 introduced Optional Chaining, a feature equivalent to the safe navigation operator found in other languages. The ECMAScript proposal for optional chaining has reached stage 4 and will be included in ES2020. Visit mdn: Optional chaining for more details.


Back in July 2017, it was mentioned by JGFMK in the comments that an ECMAScript proposal named Optional Chaining for JavaScript is in progress. Once it reaches Stage 4, it will become part of the language specification.


It's worth noting that TypeScript does not have a safe navigation or elvis operator, or anything similar as far as current knowledge goes.

To learn more about this, you can refer to the feature request at Suggestion: "safe navigation operator", i.e. x?.y. The reasoning behind not implementing it is explained in detail, citing big changes like this should happen at the ES spec committee level.

The closure on this matter is due to the fact that there isn't a specific TypeScript need for this kind of change at the expression level. It is suggested that significant operator changes should occur within the ES committee rather than independently here.

Re-evaluating would depend on a concrete ES proposal moving forward or a general consensus from the ES committee indicating a delay in implementing such a feature.

Alternative approaches include using the logical AND operator, try/catch statements, or utilizing a helper function like getSafe(() => this.myForm.name.first_name) as discussed in this post.

Answer №2

Repeatedly OR it with an empty object

When working on HTML that references properties/subproperties which may or may not exist, I find it essential to utilize safe navigation techniques.

A common challenge is accessing nested object properties like this.myForm?.name?.first_name.

The debate around the need for safe navigation in ES arises from different perspectives, but until an official Elvis operator is introduced in JS, my workaround involves using double parentheses as follows:

(((this.myForm || {}).name || {}).first_name )

This method ensures that any potential undefined values are treated as empty objects, preventing errors and allowing smooth property extraction.

Although this approach may seem cumbersome in cases of multiple tiers, it provides a cleaner alternative to chaining && operators.

For array access, OR it with an empty array

In scenarios involving arrays, such as selecting the first element from a list of names, a similar approach can be applied:

((((this.myForm || {}).names || [])[0] || {}).first_name )

Handling edge cases

Dealing with situations where elements in the chain are 0 or "" requires cautious handling. By incorporating the double parentheses technique, unexpected values like 0 or "" are managed effectively without triggering errors.

Example

The examples provided demonstrate the functionality of the workaround in different scenarios, showcasing its reliability in handling potentially missing or erroneous data.

Answer №3

Check out this alternative solution that provides a more detailed output:

const elvis = (...xs: (() => any|null)[]): any => {
    if(xs.length == 0) return null;
    const y = xs[0]();
    return xs.length == 1 || y == null ? y : elvis(...xs.slice(1));
};

const bla= {
    a : 'hello',
    b : null,
    c: undefined
}

console.log("a:", elvis(() => bla));
console.log("a:", elvis(() => bla, () => bla.a));
console.log("a:", elvis(() => bla, () => bla.a, () => bla.a.length));
console.log("b:", elvis(() => bla, () => bla.b, () => bla.b.length));
console.log("c:", elvis(() => bla, () => bla.c, () => bla.c.length));

Here is the resulting output:

> a: {a: "hello", b: null, c: undefined}
> a: hello
> a: 5
> b: null
> c: undefined

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

Prioritizing the validation of form controls takes precedence over redirecting to a different URL in Angular 2

Within an HTML page, there is a form with validation and an anchor tag as shown below: <form #loginForm="ngForm" (ngSubmit)="login()" novalidate> <div class="form-group"> <label for="email">Email</label> <i ...

Unable to modify headers after they have already been sent to the client - an error has occurred

I am encountering an issue when trying to redirect the page to another page. Everything works fine with the first post request, but starting from the second one, I keep getting this error message: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after t ...

Wait for response after clicking the button in Vue before proceeding

When the button is clicked for the first time and the data property is empty, I need to pause the button click code until an ajax response is received. Currently, when I press the button, both wait and scroll actions happen immediately without waiting for ...

When attempting to utilize VueJs v-bind:type on an input element, it appears to be ineffective when the type property name is

Code: <!DOCTYPE html> <html> <head> <title>Creating a Vue app</title> <script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3046455570021e061e0100">[ ...

How can I incorporate a feature that allows the user to restart the program from the beginning if they decide to do so?

As a beginner, I decided to create a mini mortgage calculator for practice. At the end of the code, I wanted to give users the option to either recalculate from the beginning or exit the program. I attempted to define the function as: def main(): and th ...

Tips for enhancing functionality with dependencies in Angular 2

I am working with a ParentService that has dependencies like: @Injectable() export class ParentService{ constructor(private http:Http, private customService:CustomService){} } Now, I want to create a ChildService that extends the ParentService: @Injec ...

Preventing state changes from affecting the rendering of a Material-UI table in a ReactJS application

Inside my app.js, the following code snippet defines a state: const [open,setOpen] = useState(false) This state is used to control whether a material-ui Alert should be displayed on screen for 3 seconds using this code: useEffect(()=>{ setTimeout( ...

Solving the challenge of handling multiple text inputs in Laravel Blade using Vue.js v-model within a @

Hello, I am encountering an issue with my Laravel application that displays posts and comments. The problem lies with the Vue v-model in the input text when using the @foreach directive in Blade. Each post is showing the comments input box, but when I ente ...

What is the best method for transferring data to Angular routed components?

Within one of my Angular 2 routes templates, specifically in FirstComponent, there is a button present. first.component.html <div class="button" click="routeWithData()">Pass data and navigate</div> The main objective here is to: When the ...

Tips for troubleshooting an Angular Service that is not properly injecting itself into the application

I offer a simple service: import { Injectable } from '@angular/core'; import { MdSnackBar, MdSnackBarConfig } from '@angular/material'; @Injectable() export class AlertsService { alerts: string[]; constructor(private snackBar: Md ...

confirmation box for deleting a row in a grid view

I am looking to enhance the delete confirmation box on my Gridview delete function. Currently, I am using a basic Internet Explorer box for confirmation but I want to display a more stylish confirmation box. Here is the JavaScript code snippet within my gr ...

The onDrop event in javascript seems to be failing to execute

My attempts to get the javascript onDrop event to execute when an object is dropped into a drop zone have been unsuccessful. I've tried rewriting it in various ways without any success or error messages. In my search for potential reasons why the ondr ...

Arrays in Vue Data

After creating an array and pushing data into it, the array turns into a proxy, preventing me from using JavaScript array functions on it. export default { name: 'Home', components: { PokeList, FilterType, SearchPokemon}, data() { r ...

Division of responsibilities (service and routing layers)

I'm looking to enhance my Node JS skills by improving the way I separate the service and router layers in my applications. I want to avoid code duplication, like in the case of the create method for a user scheme. In my UserService.Js file, I have th ...

What is the best way to showcase the retrieved information in my template?

After creating a file named product.ts, I proceeded to add the following code to it: export interface Product { id:number; } This is how my component looks like: export class AppComponent { title = 'angpr'; todo:Product; const ...

Looping through an object

I stumbled upon this code snippet that adds a specific property value of all blocks in a nested object to an arrays array. I'm having trouble understanding how iteration is achieved in a nested object like the one shown below using a for loop. Could ...

Trigger a new tab opening following an ajax response with Javascript

Having trouble opening in a new tab after receiving an ajax response with JavaScript, I attempted using both _newtab and _blank However, neither of them seem to be working. I wonder, Is there a solution available to find the answer? ...

Executing the setDeleted loop causes changes to the entities which are then reflected in the saveChanges

My goal is to delete a hierarchy of objects: Customer->Orders->OrderItems->OrderItemOptions I attempted to set up a nested loop to perform the operations in the correct order - deleting child records before deleting parent records as required by ...

Monitor changes in the visible price range in lightweight-chart

Is there a way to detect when the visible price range changes in lightweight-chart, similar to how the timeScale's visible time range change can be detected through subscribeVisibleTimeRangeChange? I couldn't find anything related in the document ...

Eliminate every instance using the global regular expression and the replace method from the String prototype

function filterWords(match, before, after) { return before && after ? ' ' : '' } var regex = /(^|\s)(?:y|x)(\s|$)/g var sentence1 = ('x 1 y 2 x 3 y').replace(regex, filterWords) console.log(sentence1) sentence2 ...