Determining data types through type guarding in Typescript

interface A = {
  name: string;
  ...
};

interface B = {
  name: string;
  ...
};

interface C = {
  key: string;
  ...
};

type UnionOfTypes = A | B | C | ...;

function hasName(item: UnionOfTypes) {
  if ("name" in item) {
    item; // typescript knows here that item is either A or B
  }
}

Can I automatically infer types like if("name" in item) does? My code only uses interfaces/types and not classes.

This way I wouldn't have to explicitly define

function hasName(item: UnionOfTypes): item is A | B {
  ...
}

I'm thinking of using other type guards later on, or are there reasons why narrowing down types this way should be avoided?

Answer №1

There isn't built-in support for this in TypeScript. However, you can create a custom helper function to implement type guarding. This function takes another function as input which returns either the guarded item or false.

function guard<T extends X, X>(fn: (value: X) => T | false)  {
    return function (value: X) : value is T {
        return fn(value) !== false;
    }
}

interface Person {
  name: string;
  age: number;
};

interface Animal {
  type: string;
};

type UnionOfTypes = Person | Animal;

const hasNameProperty = guard(function (item: UnionOfTypes) {
  if ("name" in item) {
    return item;
  }
  return false;
})

// Can be used with other cases as well
let stringsOrNull: Array<string | null> = ["hello", null];
let result = stringsOrNull.filter(guard(v => v ?? false));
let result2 = stringsOrNull.filter(guard(v => v ?? false));

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

I encountered an issue with Cypress when attempting to utilize a custom command. The error message "TypeError cy.login is not a function" keeps popping up. Any suggestions on how to resolve this

I am currently working on a TypeScript project and I am attempting to write some tests using Cypress. However, I encountered the following error: TypeError - cy.login is not a function. This error occurred during a before each hook, so we are skipping the ...

Omit an enum item from selection when referencing the key within the Enum

Within my enum, I have defined multiple keys: export enum MyTypeEnum { one = 'one', two = 'two', three = 'three', four = 'four' } To ensure certain types must contain these keys, I use the following ...

Issues with Angular's router outlet link functionality not performing as expected

I am encountering difficulties trying to create a link to a named router outlet in Angular. Let's focus on the most crucial part of the code: app-routing-module.ts: import { NgModule } from '@angular/core'; import { RouterModule, Routes } ...

Troub3leshooting Circular Dependency with Typescript, CommonJS & Browserify

I am currently in the process of transitioning a rather substantial TypeScript project from internal modules to external modules. The main reason behind this move is to establish a single core bundle that has the capability to load additional bundles if an ...

Experiencing a 404 ERROR while attempting to submit an API POST request for a Hubspot form within a Next.js application

Currently, I am in the process of developing a Hubspot email submission form using nextjs and typescript. However, I am encountering a couple of errors that I need help with. The first error pertains to my 'response' constant, which is declared b ...

Experience the dynamic synergy of React and typescript combined, harnessing

I am currently utilizing ReactJS with TypeScript. I have been attempting to incorporate a CDN script inside one of my components. Both index.html and .tsx component // .tsx file const handleScript = () => { // There seems to be an issue as the pr ...

Merge topics together in RxJS like zip

Is it possible to create an observable that combines two subjects in a unique way, different from the zip function? The goal is to combine two subjects so that when both have emitted values, the latest of their values is emitted. Then, after both emit at ...

What is the process for accessing getBoundingClientRect within the Vue Composition API?

While I understand that in Vue we can access template refs to use getBoundingClientRect() with the options API like this: const rect = this.$refs.image.$el.getBoundingClientRect(); I am now attempting to achieve the same using template refs within the com ...

The type undefined cannot be assigned to the type even with a null check

When looking at my code, I encounter an error stating Argument of type 'Definition | undefined' is not assignable to parameter of type 'Definition'. Even though I am checking if the object value is not undefined with if (defs[type] != u ...

Display sub-objects within Chart.js

I'm currently tackling a project in Ionic 3 where I am utilizing an API that returns a JSON response with nested objects. My goal is to display certain aspects of these objects within a bar graph using chart.js. Unfortunately, I lack experience in ma ...

Learn how to dynamically adjust context using a server-client architecture with TRPC

Currently, I am referring to the tRPC documentation for guidance on creating a server side caller. But I'm facing a challenge in dynamically setting the value when incorporating it into my NextJS 13 pages. In my context.ts file, you will find the fol ...

Make sure to verify if all values are contained within an array by utilizing JavaScript or TypeScript

These are the two arrays I'm working with. My goal is to ensure that every value in ValuesToBeCheckArr is present in ActualArr. If any values are missing from ActualArr, the function should return 0 or false. Additionally, there is an operator variabl ...

Customizing the renderInput of the Material UI DatePicker

Recently I integrated material-ui into my React project with TypeScript. I implemented the following code based on the example provided on the official website. import AdapterDateFns from '@mui/lab/AdapterDateFns'; import DatePicker from '@m ...

What is the best way to transform a JavaScript object into an array?

Here is the information I have: {product_quantity: {quantity: 13, code: "AAA", warehouse: "1000",}} The product_quantity field is part of a JSON object in a MongoDB database. I am looking to convert it into this format: {"produ ...

TypeError thrown by Mapbox markers

Looking to incorporate markers into my map using Mapbox. Below is the Angular TypeScript code I am working with: export class MappViewComponent implements OnInit { map: mapboxgl.Map; lat = 41.1293; lng = -8.4464; style = "mapbox://styles/mapb ...

Update the TypeScript definitions in the index.d.ts file using the npm command, by overriding it with the reference types

After running npm install, I noticed that the index.d.ts file contains a reference to the wrong path: /// <reference types="[WrongPath]"/>. As someone new to npm, TypeScript, and web development in general, I'm wondering if it's possible t ...

Is there a way for me to view the output of my TypeScript code in an HTML document?

This is my HTML *all the code has been modified <div class="testCenter"> <h1>{{changed()}}</h1> </div> This is my .ts code I am unsure about the functionality of the changed() function import { Component, OnInit } f ...

Attempting to retrieve data either by code or with a WHERE condition proves unsuccessful as the data retrieval process yields no results

Seeking assistance with my Angular project that is utilizing a Node.js server and MSSQL express. I am having trouble retrieving data using a WHERE condition in my code. Any help in identifying the missing piece or error would be appreciated. Thank you. // ...

What is the reason for the failure of the "keyof" method on this specific generic type within a Proxy object created by a class constructor?

I'm encountering difficulties when utilizing a generic type in combination with keyof inside a Proxy(): The following example code is not functioning and indicates a lack of assignable types: interface SomeDataStructure { name?: string; } class ...

Tips for validating nominal-typed identifiers

I recently started experimenting with the enum-based nominal typing technique explained in more detail at this link. enum PersonIdBrand {} export type PersonId = PersonIdBrand & string interface Person { id: PersonId firstName: string lastName: ...