Executing secure journey within TypeScript

Just came across an enlightening article on Medium by Gidi Meir Morris titled Utilizing ES6's Proxy for secure Object property access. The concept is intriguing and I decided to implement it in my Typescript project for handling optional nested objects while maintaining type checking.

To transform optional nested objects into mandatory ones, I am utilizing the following type:

export type DeepRequired<T> = {
    [P in keyof T]-?: DeepRequired<T[P]>;
};

The TypeScript code provided by Gidi (with some clever workarounds...):

export interface Dictionary {
   [key: string]: any;
};

const isObject = (obj: any) => obj && typeof obj === 'object';
const hasKey = (obj: object, key: string) => key in obj;

const Undefined: object = new Proxy({}, {
   get: function (target, name) {
       return Undefined;
   }
});

export const either = (val: any, fallback: any) => (val === Undefined ? fallback : val);

export function safe<T extends Dictionary>(obj: T): DeepRequired<T> {
   return new Proxy(obj, {
       get: function(target, name){
           return hasKey(target, name as string) ? 
           (isObject(target[name]) ? safe(target[name]) : target[name]) : Undefined;
       }
   }) as DeepRequired<T>;
}

Example of its usage:

interface A {
   a?: {
       b?: {
           c?: {
               d?: string
           }
       }
   },
   b: boolean,
   c?: {
       d: {
           e: number
       }
   },
   d?: Array<{e: boolean}> 
}
const obj: A = {b: false};
const saferObj = safe(obj);

This approach effectively handles various scenarios without causing TS errors:

test('should work for nested optional objects', () => {
   expect(either(saferObj.a.b.c.d, null)).toEqual(null);
   expect(either(saferObj.a.b.c.d, undefined)).toEqual(undefined);
   expect(either(saferObj.a.b.c.d, 322)).toEqual(322);
});

test('should work for required members', () => {
   expect(either(saferObj.b, null)).toEqual(false);
});

test('should work for mixed optional/required tree', () => {
   expect(either(saferObj.c.d.e, null)).toEqual(null);
});

When it comes to arrays...

test('should work for arrays', () => {
   expect(either(saferObj.d[0].e, null)).toEqual(null);
});

An error thrown by the TS compiler states:

[ts] Element implicitly has an 'any' type because type 'DeepRequired<{ e: boolean; }[]>' has no index signature.

Any suggestions on how I can resolve this issue with Arrays?

Answer №1

If your project is using Typescript 2.9 or newer, your code should run without any issues. This is because Typescript 2.9 introduced a change in the keyof operator to include numeric, symbol, and string keys. Previously, only string keys were returned by keyof.

For those still on version 2.8, there is a workaround available. You can handle arrays explicitly within the DeepRequired type by utilizing conditional types.

export type DeepRequired<T> = {
    [P in keyof T]-?: T[P] extends Array<infer U>?Array<DeepRequired<U>>: DeepRequired<T[P]>;
};

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

Trouble with Bootstrap Collapse feature not collapsing on its own

I recently added a Bootstrap collapse feature to my payment view in Laravel. The Bootstrap section collapses when clicked, but I would like it to be collapsed by default. I understand that I need to include: aria-expanded="false" However, it still doesn& ...

Make sure to leave a space after a period in a sentence, but do

My question is about fixing spacing issues in text, specifically sentences that lack spaces after a dot. For example: See also vadding.Constructions on this term abound. I also have URLs within the text, such as: See also vadding.Constructions on th ...

sending parameters to a callback function that is listening for arguments

function setmclisten(message, sender, sendResponse) { console.log(data); if(message['type'] === 'startUp') { console.log(data); sendResponse(data) } } function QuarryToServer(){ chrome.runtime.onMessage.removeListener( ...

Trouble with Typescript in VSCode made easy

Setting up a VSCode environment for working with TypeScript v2.03 has been challenging. Beginning with a simple vanilla javascript snippet that can be tested in node via the integrated terminal. function Person() { this.name = ""; } Person.prototy ...

What is the most effective method for populating an array with all images from a particular directory?

I recently installed a pdf viewer plugin on my website (check it out here: ), and I have a question regarding its functionality. I am looking to include approximately 60 - 70 pages in this flip book, but I am unsure of how to proceed. I have attempted var ...

Generate a fresh JSON object following a click event triggered by an HTTP PUT request

I have the following structure in JSON format: "disputes": [ { id: "", negotiation_type: "", history:{ user_flag: "", created_at: "", updated_at: "", created_by: null, updated_by: null, ...

Have the functionality of right clicking and selecting Paste work in the input field using style=text and a button

Here is the code I am using: <script type="text/javascript"> $(document).ready(function() { $('#submit').prop('disabled', true); $('#links').change(function() { $('#submit').prop('disabled ...

Encountering issues with link functionality on homepage due to React-Router v6 and Material-UI Tab integration

I'm currently working on a homepage that requires different page links. Below you can find the necessary code snippet for setting up the tabs and routes for each page: <li> The tabs are located here - <Link to="/demo">D ...

Tips for eliminating additional white space within a bootstrap row

I'm having trouble removing the extra space on my website while using Bootstrap 5. I've tried various Bootstrap classes like pr-0, mr-0, p-auto, m-auto but none of them seem to work. I also attempted using CSS margin-right: 0; but that didn' ...

I am in need of creating a specialized Gulp task that can effectively strip out attributes from my HTML code

I am in need of a Gulp task that can iterate through all specified HTML documents and eliminate specific attributes (such as style=""). I initially attempted to accomplish this task the same way I would do it via the browser, but it seems that's not p ...

No testing detected, ending with code zero - NPM and YARN

After installing node js and yarn, I attempted to run an application/script developed by someone else. However, when running the test, I encountered the following message: No tests found, exiting with code 0 Watch Usage › Press f to run only failed tes ...

"Resetting count feature in AngularJS: A step-by-step guide

I have a list consisting of four items, each with its own counter. Whenever we click on an item, the count increases. I am looking to reset the counter value back to zero for all items except the one that was clicked. You can view the demonstration here. ...

Angular2: Continuous User Authentication Guard

I am in the process of developing an application that requires strict authentication for all users. To enforce this, I have created a LoggedInGuard. However, I find myself having to include canActivate: [LoggedInGuard] in every route definition within my ...

Personalize the "set up notification" PWA on React

Is it possible to customize this default design, including the picture, title, description, and background? I made changes in manifest.json, but nothing seems to have happened. Here is a picture of the random install prompt that I would like to customize ...

What is the best method for linking an HTML file to CSS, javascript, and image files?

I need assistance with running an HTML file along with its source files that I downloaded from the server. The HTML file is located in NSCachesDirectory and here is the code snippet I am using. Can someone please help me figure this out? NSArray *paths ...

What could be causing my JavaScript function to produce repeated letters with just one key press?

After implementing a code that generates different variables based on the 'truth' variable, I encountered an issue. Everything works flawlessly when 'truth' is set to "name," but as soon as I switch it to "email," any keystroke results ...

How do I use NodeJS and MongoDB to dynamically populate my webpage with data from a database?

I am working on a small express + ejs application that stores data for registered users. Each user is assigned a "role" that is stored in the database. I would like to display each user's information in an html div, with the div's color refle ...

Converting a file into a blob or JavaScript file in NodeJS: A step-by-step guide

I have a function that is designed to accept a file in this particular format using the multer package. Now, my goal is to upload this file to Firebase storage, but before I can do that, it needs to be converted into either a Blob or a Javascript file. Th ...

A captivating opportunity for a web developer specializing in frontend design

Encountered an intriguing dilemma that has me stumped. There is a single stipulation: Only the json can be altered! I am struggling to meet this requirement: data.hasOwnProperty("\u{0030}") class JobHunter { get data() { return &ap ...

Encountered a PrismaClientValidationError in NextJS 13 when making a request

I am currently working on a school project using NextJS 13 and attempting to establish a connection to a MYSQL database using Prisma with PlanetScale. However, when trying to register a user, I encounter the following error: Request error PrismaClientValid ...