Is there a way to eliminate the undefined and null types from an object in typescript by specifying a list of keys?

After extensive work, I've managed to develop a function that fulfills the vital runtime requirement of checking for null and undefined not being true:

 function checkFieldsExistence<T>(obj: T | T[], ...fields: (keyof T)[]): boolean {
    const inObj: { (obj: T): boolean } = (obj) => fields.every((f) => obj[f] != null);

    if (Array.isArray(obj)) {
        return obj.every((o) => inObj(o));
    } else {
        return inObj(obj);
    }
}

However, my ultimate goal is to create a functionality that can either update an object with a new type, or allow me to leverage this within an if statement and have the types updated dynamically within the context of the if statement.

I've come across similar queries like this one on StackOverflow: Typescript type RequireSome<T, K extends keyof T> removing undefined AND null from properties, but it doesn't quite cater to a list of fields as required.

For reference, the fields in question are known during compile time.

Answer №1

The RequireAndNotNullSome type is ready to be used in your specific scenario. To transform hasFields into a type guard, you must include a type parameter (referred to as K) to capture the actual keys passed to the function. In order to make it work with both arrays and objects, separate overloads are required for each case:



type RequiredAndNotNull<T> = {
    [P in keyof T]-?: Exclude<T[P], null | undefined>
}

type RequireAndNotNullSome<T, K extends keyof T> = 
  RequiredAndNotNull<Pick<T, K>> & Omit<T, K>

function hasFields<T, K extends keyof T>(obj: Array<T | RequireAndNotNullSome<T, K>>, ...fields: K[]): obj is Array<RequireAndNotNullSome<T, K>>
function hasFields<T, K extends keyof T>(obj: T | RequireAndNotNullSome<T, K> , ...fields: K[]): obj is RequireAndNotNullSome<T, K>
function hasFields<T, K extends keyof T>(obj: T | Array<T>, ...fields: K[]): boolean{
    const inObj: { (obj: T | RequireAndNotNullSome<T, K>): boolean } = (obj) => fields.every((f) => obj[f] != null);

    if (Array.isArray(obj)) {
        return obj.every((o) => inObj(o));
    } else {
        return inObj(obj);
    }
}

type Question = {
    id: string;
    answer?: string | null;
    thirdProp?: number | null;
    fourthProp?: number | null;
}

declare var v: Question;

if (hasFields(v, "answer", "thirdProp")) {
  v.answer.anchor // string 
}

declare var arr: Question[];

if (hasFields(arr, "answer", "thirdProp")) {
  arr[0].answer.anchor // string 
}

Access Playground Link

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 best way to differentiate the handling of a 401 Unauthorized response from other errors within an Angular 8 service that utilizes RxJS?

My REST API implementation requires an access token for user identification with each call. If the token is missing or expired, the endpoint returns a 401 UNAUTHORIZED response. There are instances where I make API calls using a timer in my service class: ...

Sending data to a React component from regular HTML

I have a question about implementing a method to pass custom attributes from HTML elements as props to React components. Here's an example: function someFunction(props) { return <h1>props.something</h1> } HTML: <div id="someEl ...

Tips for addressing the issue - error TS2451: Unable to redefine block-specific variable 'total'

I am currently working on setting up the Jest testing framework and running a basic test (using an example from jestjs.io). Here is the content of the sum.ts file: function sum(a: any, b: any):any { return a + b; } module.exports = sum; And here is the ...

Steps to display a modal dialog depending on the category of the label

I'm encountering an issue where clicking on different labels should show corresponding modal dialogs, but it always displays the same modal dialog for both labels ("All Recommendations"). Can anyone offer guidance on how to resolve this problem? Thank ...

The outcome of TypeScript is ES5 JavaScript code

How can I configure TypeScript to output classes, consts, lets, etc., instead of converting everything to vars and functions? My TypeScript version is 2.4.1. Below is my current tsconfig file: { "compilerOptions": { /* Basic Options */ "target" ...

Unable to export Interface in Typescript - the specific module does not offer an export named Settings

I am encountering an issue while trying to export/import an interface in Typescript. The error message I receive is causing confusion as I'm unsure of where I went wrong. Uncaught SyntaxError: The requested module '/src/types/settings.ts' ...

Setting default parameters for TypeScript generics

Let's say I define a function like this: const myFunc = <T, > (data: T) => { return data?.map((d) => ({name: d.name}) } The TypeScript compiler throws an error saying: Property 'name' does not exist on type 'T', whic ...

Is there a way to customize the text color highlight for a specific react component only?

I'm working with React and need to adjust the text highlight color. Initially, I tried this approach: Highlight.css ::selection { background:#fbc308; color: black } somecomponent.tsx import './highlight.css' However, this ende ...

Tips on utilizing a function that was generated within the constructor

I'm currently in the process of developing a function within the constructor, and it is essential that this function be placed inside the constructor. I am interested in implementing a button to trigger this function from an external source, but unfor ...

Using vuex-class to interact with Vuex in non-Vue components

Is it possible to access Vuex outside of a Vue component using vuex-class? In a typical scenario, the process is quite straightforward: // some JS file import store from './../store'; // path to Vuex store store.commit('ux/mutationName&ap ...

The values of the data members remain static within the Typescript environment

In my Ionic 2 project, I have a class structured like the one below. Instead of using the Ionic Native geolocation plugin, I am working with the locationServices plugin. export class LocationManager{ locationAcquiring:boolean; locationAvailable:b ...

What specific category does the enum object fall under?

How can I create a wrapper class for a collection of elements in an enumeration? export class Flags<ENUMERATION> { items = new Set<ENUMERATION>(); enu; // what type ? constructor(enu) { // what type ? ...

Unable to find nonexistent names when running `vite npm run dev`

Running npm dev is not showing any errors for missing names. To replicate the issue, follow these steps: Create a React/TypeScript application named "foobar" by running: $ npm create vite@latest Need to install the following packages: [email protecte ...

Checkbox in Angular FormGroup not triggering touched state

There seems to be an issue with the Angular form when checking if the form is touched, especially in relation to a checkbox element. Despite the value of the checkbox changing on click, I am seeing !newDeviceGroup.touched = true. I'm not quite sure wh ...

How to transfer the label text value from html to .ts file in Ionic 3?

Hey everyone! I just started using Ionic and I'm wondering how to pass the value of a label text from HTML to the .ts file. Here's a snippet of my code: <div class="box" (click)="openChatBot()"></div> <ion-label>LEADER ...

Angular: proper dependency injection may not occur when appending .js or .ts at the end of an import statement

When it comes to import statements, the format is usually as follows: import {HelpService} from '../../help.service' It's worth noting that if I utilize autowiring to inject HelpService into the constructor, an already existing instance of ...

What is the best way to implement multiple ternary operators within HTML code?

Consider the following code snippet: It currently applies CSS classes up to red4, but I want to apply CSS classes up to red11. Additionally, the variable "size" in myData should be dynamic. For example, size could range from 0-20 // 0-100 // 0-10000, etc., ...

Puzzled by the specialized link feature

As I delve into the world of React and Next.js, I find myself working on the link component. Initially, I had a grasp on basic routing in next.js which seemed pretty straightforward. However, things took a confusing turn when I stumbled upon this code: imp ...

Define an object type in Typescript that includes both specified properties and an unlimited number of unspecified properties

I'm attempting to create a custom data type using the code below, but it's not working: type CustomDataType { [key: string]: CustomDataType; isValid: boolean; errors?: string[]; } My goal is to have a CustomDataType with an isValid propert ...

The unbeatable combination of Vuex and Typescript

I am currently in the process of converting a JavaScript project to TypeScript. However, I have encountered a type error when attempting to integrate Vuex with Vue. import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); https://i.sstatic.net/e7 ...