Ensuring the Existence of Variables Based on Parameterized Type in TypeScript Return Type Declaration

Within my TypeScript class called Design, there is a method named checkFetched. This method's purpose is to verify the existence of a property of type DesignData within an instance of the class, based on a parameterized type called Filename. Here is a simplified version of the code:

type Filename = 'original' | 'result'
type DesignData = {
  id: string
  // ...
}

export class Design {
  original?: DesignData
  result?: DesignData

  checkFetched(target: Filename): this is { [K in typeof target]: DesignData } {
    return !!this[target]
  }

  private async loadDesign(fileName: Filename) {
    if (!this.checkFetched(fileName)) return
    const shouldNotHaveUndefined = this[fileName]
    const shouldHaveUndefined1 = this.original
    const shouldHaveUndefined2 = this.result
  }

  private async loadDesign2() {
    if (!this.checkFetched('original')) return
    const shouldNotHaveUndefined = this.original
    const shouldHaveUndefined = this.result
  }
}

The checkFetched method currently returns a boolean value indicating the presence or absence of the specified property. However, I aim to enhance the return type of this method so that when the check is successful, TypeScript infers that the corresponding property is not undefined, while other properties may still be undefined.

For instance, after invoking checkFetched('original') in the loadDesign2 method, TypeScript should recognize that shouldNotHaveUndefined is not undefined, but shouldHaveUndefined1 and shouldHaveUndefined2 could potentially be undefined. At present, shouldHaveUndefined is treated as non-undefined.

I have tried various approaches, with the expectation that by refining the return type, TypeScript would correctly infer the existence of the property post calling checkFetched.

I am reaching out to the community for suggestions on how to tweak this approach to meet my requirements or to ascertain if achieving this goal is inherently unattainable in TypeScript.

To delve further into this topic and share your insights, please visit the TypeScript Playground

Answer №1

The current outcome of your checkFetched function is too general, as it indicates that any property with a name from the Filename union (specifically original and result) is not undefined. However, you aim to inform TypeScript that only the property with the exact name in target should be considered not undefined. To achieve this, you need to make the function generic:

checkFetched<Target extends Filename>(target: Target): this is { [K in Target]: DesignData } {
    return !!this[target];
}

(Alternatively, instead of using

this is { [K in Target]: DesignData }
, you can opt for
this is Record<Target, DesignData>
, which might provide better clarity based on personal preference.)

With these changes, the checks will function as intended:

private async loadDesign<Target extends Filename>(fileName: Target) {
    if (!this.checkFetched(fileName)) return;
    const shouldNotHaveUndefined = this[fileName];
    console.log(shouldNotHaveUndefined.id); 
    const shouldHaveUndefined1 = this.original;
    const shouldHaveUndefined2 = this.result;
}

private async loadDesign2() {
    if (!this.checkFetched("original")) return;
    const shouldNotHaveUndefined = this.original;
    const shouldHaveUndefined = this.result;
}

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

Node OOM Error in Webpack Dev Server due to Material UI Typescript Integration

Currently in the process of upgrading from material-ui v0.19.1 to v1.0.0-beta.20. Initially, everything seems fine as Webpack dev server compiles successfully upon boot. However, upon making the first change, Node throws an Out of Memory error with the fol ...

Issue with TypeScript: Difficulty accessing keys in a recursive manner

I've created a custom type that eliminates any nullish values when working with objects. export type ExcludeNullish<T> = Exclude<T, null | undefined>; export type ExcludeNullishKeys<T> = { [K in keyof T]-?: T[K] extends boolean | ...

Exploring the wonders of utilizing `instanceof` in TypeScript

Looking at this simple node+ts code: import * as express from "express"; function processRequest(app: express.Application) { if (!(app instanceof express.Application)) throw new TypeError(); // additional logic here... } When I check the code in VSC ...

Set up a TypeScript project with essential dependencies for creating multiple raw JavaScript output files

Currently, I am in the process of developing scripts for Bot Land, a real-time strategy game that offers a unique gameplay experience. Rather than controlling units traditionally with a mouse and keyboard, players code their bots using an API to engage in ...

Python's yield functionality facilitates the creation of lightweight generators, allowing

Request is being sent from the front end to trigger the backend method. In Python Flask, the backend method utilizes a generator and yield to iterate through a list of 100000 elements, sending each element one by one to the front end. The goal is for the b ...

Try querying again if you receive no results from an http.get request in Angular using RXJS Operators

In my Angular service, I sometimes encounter an issue where I receive an empty array. In such cases, I would like to trigger a fresh query. let request = this.http.post(this.searchlUrl, payload).pipe( retryWhen(errors => errors.pipe(delay(100 ...

VS Code fails to identify Typescript internal modules

I am currently facing issues with separating my TypeScript classes into distinct files using internal modules. Unfortunately, the main.ts file is not loading or recognizing the sub-modules. main.ts /// <reference path="Car.ts" /> module Vehicles { ...

Using Dynamic Imports in Angular 6 Libraries

After creating a sample Angular 6 Library using the Angular CLI, I have the basic structure with the library "my-lib" and the sample app "test-lib" for testing purposes. Within the library, I am looking to implement dynamic imports. Specifically, I have a ...

Exploring ways to conduct a thorough scan of object values, inclusive of nested arrays

My goal is to extract all values from an object. This object also includes arrays, and those arrays contain objects that in turn can have arrays. function iterate(obj) { Object.keys(obj).forEach(key => { console.log(`key: ${key}, value: ${o ...

Revamp Your Service Naming and Nickname with Swagger Codegen IO

Is it possible to customize the Swagger IO CodeGen naming conventions for generating Angular API Service Proxies? Check out Swagger Editor here The current convention combines API, Controller Name, Controller Method, and HTTP Action. public apiProductGet ...

How can I use the form's restart() method in React-Final-Form to clear a MUI TextField input and also capture the event at the same time?

When I use form.restart() in my reset button, it resets all fields states and values based on my understanding of the Final-Form. The reset method triggers and clears all fields in the form, and I can capture the event in the autocomplete. However, I am fa ...

How should a child component specify the type of component being passed in props?

Consider the following snippet from App.tsx : <Layout header={ <Header/> } </layout> Now, let's take a look at the Layout component : export default function Layout({header, body}: any) { return ( <div className="layou ...

What is the best way to reference a module within my own code in TypeScript running on Node.js

Currently, I have two modules named 'json' and 'json-object'. The 'json' module consists of all objects extending the default JSON object in JSON format: import { JSONObject } from './json-object'; export abstract ...

Utilizing the onBlur event to control focus within a React element

In the React component I'm working on, I have implemented an onBlur event handler. The logic inside this handler is supposed to return focus back to the target element. This code is written in TypeScript. emailBlur(e: React.FocusEvent<HTMLInputEle ...

Leveraging AWS CDK to seamlessly integrate an established data pipeline into your infrastructure

I currently have a data pipeline set up manually, but now I want to transition to using CDK code for management. How can I achieve this using the AWS CDK TypeScript library to locate and manage this data pipeline? For example, with AWS SNS, we can utilize ...

The parent component can successfully call the setState function, but for some reason, the

In my code structure, I have the following setup (simplified): Here is the parent component: //code... const {handleClick} = useClick; <ul> {actions.map((action: string) => ( <li onClick={() => handleClick()} key={uuidv4()}> ...

Measuring Feedback: Utilizing Angular 4 to calculate review ratings

I'm facing a challenge while working on a review form using Firebase and Angular 4. The issue is with calculating the total length of added reviews and the sum of their ratings. Each time a new review is submitted, it gets pushed to a list of objects ...

Ways to troubleshoot and resolve the npx create-next-app issue

Every time I try to create a new app using npx create-next-app@latest --typescript, it keeps giving me this error message: npm ERR! code ENETUNREACH npm ERR! syscall connect npm ERR! errno ENETUNREACH npm ERR! request to https://registry.npmjs.org/create-n ...

If the input is unmounted in react-hook-form, the values from the first form may disappear

My form is divided into two parts: the first part collects firstName, lastName, and profilePhoto, while the second part collects email, password, confirmPassword, etc. However, when the user fills out the first part of the form and clicks "next", the val ...

Rotating display for showcasing various portfolios

I'm facing an issue with my portfolio images carousel using a map in Bootstrap. When I navigate from one portfolio (e.g. image 4) to another (which has only one image), the carousel shows up blank because the active carousel-item is at index 3 (image ...