Unveiling typescript property guards for the unknown data type

Is there a way to type guard an unknown type in TypeScript?

const foo  = (obj: unknown) => {
    if (typeof obj === 'object' && obj) {
        if ('foo' in obj && typeof obj.foo === 'string') {
            return obj.foo;
        }
    }
};

However, I am encountering an issue

Property 'foo' does not exist on type 'object'.

I also tried using the is expression but it doesn't work as expected:

const foo  = (obj: unknown): obj is { foo: 'string' } => {
    if (typeof obj === 'object' && obj) {
        if ('foo' in obj && typeof obj.foo === 'string') {
            return obj;
        }
    }
    throw new Error();
};

Answer №1

To improve the functionality of TypeScript, you may need to provide some assistance:

type customObj = object & { custom: unknown };
const customFunction = (obj: unknown) => {
    if (typeof obj === 'object' && obj) {
        if ('custom' in obj && typeof (obj as customObj).custom === 'string') {
            return (obj as customObj).custom;
        }
    }
};

Answer №2

Consider implementing this helper function:

const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop)
  : obj is Obj & Record<Prop, unknown> =>
  Object.prototype.hasOwnProperty.call(obj, prop);

for your specific scenario. The in operator typically works well with unions. Refer to this link, here, and here

Functional code snippet:

const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop)
  : obj is Obj & Record<Prop, unknown> =>
  Object.prototype.hasOwnProperty.call(obj, prop);

const foo = (obj: unknown) => {
  if (typeof obj === 'object' && obj) {
    if (hasProperty(obj, 'foo') && typeof obj.foo === 'string') {
      return obj.foo;
    }
  }
};

Playground

If you wish to throw an error when obj is invalid, utilize the assert function:

const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop)
  : obj is Obj & Record<Prop, unknown> =>
  Object.prototype.hasOwnProperty.call(obj, prop);

function foo(obj: unknown): asserts obj is { foo: string } {
  const isValid =
    typeof obj === 'object' &&
    obj &&
    hasProperty(obj, 'foo') &&
    typeof obj.foo === 'string';

  if (!isValid) {
    throw new Error();
  }

};

declare var obj: unknown;

foo(obj);

obj.foo // ok

Playground

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

Pull in class definitions from the index.js file within the node_modules directory

In my project, I have the package called "diagram-js" in the node_modules. The file node_modules/diagram-js/lib/model/index.js contains multiple class definitions as shown below: /** * @namespace djs.model */ /** * @memberOf djs.model */ /** * The b ...

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)) ...

Error message appears when trying to render a shallow mock of a React.Component that extends MyInterface with any type

Encountering an Issue with Component Mocking When attempting to mock a component, I am receiving the following error message: "Conversion of type '{ props: { index: number; AssignmentTitle: string; AssignmentDescription: string; AssignmentUtilizedHou ...

Can data from an Angular app be accessed by an external JavaScript code within the same project?

I've been thinking about a theoretical scenario that luckily I haven't encountered yet. Imagine I have an Angular Project compiled in My PROJECT FOLDER. <br/> Inside this PROJECT FOLDER, there's another JAVASCRIPT FILE external to ...

Electron and React: Alert - Exceeded MaxListenersWarning: Potential memory leak detected in EventEmitter. [EventEmitter] has 21 updateDeviceList listeners added to it

I've been tirelessly searching to understand the root cause of this issue, and I believe I'm getting closer to unraveling the mystery. My method involves using USB detection to track the connection of USB devices: usbDetect.on('add', () ...

Managing HTTP errors using async/await and the try/catch block in a React application with TypeScript

Below is a snippet of code I am working with! import React, { useState } from "react"; function App() { const [movies, setMovies] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState<string ...

Having difficulties generating ngc and tsc AOT ES5 compatible code

I've explored various options before seeking help here. I have an angular2 library that has been AOT compiled using ngc. Currently, I am not using webpack and solely relying on plain npm scripts. Below is the tsconfig file being utilized: { "comp ...

In Angular Google Maps, here's a step-by-step guide on how to zoom in

I am currently utilizing agm/core to showcase the coordinates of a map. Here is the code snippet I am using: <agm-map [latitude]="10.3207886" [longitude]="123.90250049999997"> <agm-marker [latitude]="10.3207886 [longitude]="123.90250049999997 ...

TypeScript is encountering difficulty locating a node module containing the index.d.ts file

When attempting to utilize EventEmitter3, I am using the following syntax: import EventEmitter from 'eventemitter3' The module is installed in the ./node_modules directory. It contains an index.d.ts file, so it should be recognized by Typescrip ...

Help with Material-UI: Passing unique props to a custom TreeItem component

I am trying to pass an argument category to the component CustomTreeItem which uses TreeItemContent. Documentation: https://mui.com/ru/api/tree-item/ import TreeItem, { TreeItemProps, useTreeItem, TreeItemContentProps, } from '@material-ui/lab ...

Is there a way to resolve the issue of retrieving the processed value directly in NestJS's @OnEvent function?

Due to excessive logic in the API and its slow performance, I have resorted to handling some of the logic with @OnEvent. The problem arises when the frontend runs the @GET API immediately after this API, potentially without waiting for @OnEvent to update. ...

Full compatibility with Angular 2 is now available on Visual Studio 2015 with the added support of

I have some inquiries regarding Visual Studio 2015, Resharper 10, and Angular 2. Is there any syntax highlighting support for HTML markup in TypeScript files in Visual Studio 2015 or Resharper 10? For example, when using a multiline string in a componen ...

Setting the [required] attribute dynamically on mat-select in Angular 6

I'm working on an Angular v6 app where I need to display a drop-down and make it required based on a boolean value that is set by a checkbox. Here's a snippet of the template code (initially, includeModelVersion is set to false): <mat-checkbo ...

Ways to retrieve the property of an object within a view while being sourced from an observable

I am currently working with the following provider code: getWorldCities2() { return this.http.get('../assets/city.list.json') .map(res => res.json()); } Within my TypeScript code, I have implemented the following: ionViewDidLoad() { ...

Execute TSC on the Hosted Build Agent

Currently, I am diving into TypeScript and have managed to create a basic app that I would like to deploy using VSTS on Azure App Service. My straightforward build definition involves the following steps: Utilize "Node Tool Installer (preview)" to set up ...

Can we specify the type of a destructured prop when passing it as an argument?

I have implemented Material UI's FixedSizeList which requires rendering rows in the renderRow function and passing it as a child to the component. The renderRow function accepts (index, style, data, scrolling) as arguments from the FixedSizeList comp ...

Styles are not applied by Tailwind to components in the pages folder

NextJS project was already created with tailwind support, so I didn't have to set it up myself. However, when I add className to an HTML element in a component within the pages/ folder, it simply doesn't work, even though the Elements panel in D ...

How can we avoid printing out undefined data from an Observable in Angular 2?

Here is the code I have in my service: fetchUserData(userId: string): Observable<any> { return this.http.get('https://jsonplaceholder.typicode.com/todos/' + userId) .map((response: Response) => { const userData = ...

How to show specific images by clicking on particular items in Ionic 3 on a separate page

Can someone assist me with displaying specific images from a slider gallery? I am struggling to figure out how to show only the January edition when clicking on it in eighteen.html, while hiding the February and March editions. It has been 2 days of unsucc ...

What could be causing the Typescript error when utilizing useContext in combination with React?

I am currently working on creating a Context using useContext with TypeScript. I have encapsulated a function in a separate file named MovieDetailProvider.tsx and included it as a wrapper in my App.tsx file. import { Context, MovieObject } from '../in ...