How can I verify the value of a class variable in TypeScript by using a method?

I need a more concise method to inform TypeScript that my client has been initialized (no longer null). While I have achieved this functionality, the current implementation seems unnecessarily verbose. Here is how it currently looks:

export abstract class CacheService {
    storeClient: ICacheStoreInterface | null = null

    protected constructor(storeClientGetter: () => Promise<ICacheStoreInterface>) {
        this.logger = Container.get(Logger)
        void this.initialize(storeClientGetter)
    }

    private checkInitialization(client: ICacheStoreInterface | null): asserts client is ICacheStoreInterface {
        if (!this.storeClient) {
            throw new Error('Attempting to access cache before initialization')
        }
    }

    private async initialize(storeClientGetter: () => Promise<ICacheStoreInterface>) {
        try {
            this.storeClient = await storeClientGetter()
        } catch (error) {
            this.logger.error(`Error initializing cache service:\n${error}`)
        }
    }

    public async set(key: storeKey, value: any) {
        this.checkInitialization(this.storeClient)
        await this.storeClient.set(key, value)
    }

    public async get(key: storeKey) {
        this.checkInitialization(this.storeClient)

        return this.storeClient.get(key)
    }
}

export interface ICacheStoreInterface {
    get(key: storeKey): Promise<any>
    set(key: storeKey, value: any): Promise<void>
}

export type storeKey = number | string | symbol

TS playground link

The goal is to achieve the same outcome without explicitly passing this.storeClient to the checkInitialization method. It seems feasible since both the method and the parent function have access to the variable. Is there a way for them to share type data automatically? Essentially, I am seeking something like

asserts this.storeClient is ICacheStoreInterface
, although that exact example may not work. Is it possible, or will I need to accept the minor inconvenience of this seemingly "pointless" variable?

Answer №1

There is currently no built-in support for type predicates like `arg.prop is Type`, or for assertion predicates such as `asserts arg.prop is Type`. A feature request has been submitted for this functionality, specifically for type predicates, in the microsoft/TypeScript repository #11117. However, it is still pending feedback from users. Feel free to show your support by giving a thumbs up and providing details of your use case.

While directly using statements like

asserts this.storeClient is ICacheStoreInterface
is not possible, you can achieve similar behavior with
asserts this is {storeClient: ICacheStoreInterface}
, or alternatively with
asserts this is this & {storeClient: ICacheStoreInterface}
. The latter option might be necessary depending on strict narrowing requirements imposed by the compiler.

private checkInitialization(): asserts this is { storeClient: ICacheStoreInterface } {
    if (!this.storeClient) {
        throw new Error('Attempting to access cache before initialization')
    }
}

public async get(key: storeKey) {
    this.checkInitialization()
    // this is now this & { storeClient: ICacheStoreInterface; }
    return this.storeClient.get(key) // okay
}

Note that property type guards are ineffective when applied to private properties since assigning an object with a private property to one with a public property leads to `never` narrowing. Therefore, this technique has its limitations in certain scenarios.

Access Playground link here

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

Issue in Typescript: The method `clear` or `send` is not recognized in type `unknown` within Protractor framework

Having trouble using clear and sendKeys in Protractor with TypeScript. Could it be that I am missing certain dependencies, as even the click function is giving errors? I have attempted various solutions from Protractor clear() not working, but unfortunate ...

Sending data from view to controller in Angular using TypeScript

I am currently working with AngularJS and TypeScript, and I have encountered an issue with passing a parameter from the view to the controller. In my attempts to solve this problem, I have utilized ng-init as follows: <div class="col-md-9" ng-controlle ...

What is the process for overloading a Vue component decorator in a TypeScript environment?

I enjoy using Vue with TypeScript decorators: import { Component, Prop, Vue, Watch } from 'vue-property-decorator'; @Component({ components: { .. }, ... }) ... Is it possible for me to add a custom property to pass to the decorator in this ...

What purpose does the class serve in typescript?

This is a unique version of app.component.ts in the Angular Tour of Hero tutorial. import { Component } from '@angular/core'; export class Superhero{ name : string; id : number; } const SUPERHEROES : Superhero[] = [ {name : 'Wonder ...

Avoiding redundant EventEmitters when transferring @Output to a child component

While working on a form component, I decided to separate the form action buttons into a child component. This led me to create two EventEmitter and handlers for the same action. I'm wondering if there is a way to directly pass the 'onDiscard&apo ...

A TypeScript function that returns the ReturnType of a specific callback function

Is it possible to define an annotation for a function that accepts a callback, and have the function return type determined by the callback's return type? // Suppose the callback takes a number as argument function processCallback(cb: (arg:number) =&g ...

Encountering a "No exported member" error while attempting to include & { session: Express.Session } in the MyContext type while following a tutorial on React, Express, and Typescript

Currently exploring a React, Express, and Typescript tutorial, which is still quite new to me. I am trying to grasp the concept of setting up custom types, and this is what I have so far. In my types.ts file: import { Request, Response } from "expres ...

Has an official Typescript declaration file been created for fabric.js?

Currently, I have come across a Typescript definition for fabric.js on https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/fabric (https://www.npmjs.com/package/@types/fabric). However, its official status is unclear. Does anyone have more ...

The service being injected is not defined

Two services are involved in this scenario, with the first service being injected into the second service like so: rule.service.ts @Injectable() export class RuleService { constructor( private _resourceService: ResourceService ){} s ...

I'm having trouble retrieving the object value from a different function within my Typescript and Express application

Currently I am experimenting with utilizing typescript alongside express for my application development. I have created a function that I intend to utilize in various sections of my codebase. Upon invoking the function, I am able to observe the values thro ...

To trigger a Bootstrap 5 modal in a child component from a button click in the parent component in Angular without the need to install ng-bootstrap is possible with the following approach

To achieve the functionality of opening a modal in a child component upon clicking a button in the parent component without using ngx-bootstrap due to restrictions, one approach is to add data-bs-target and data-bs-toggle attributes to the button. Addition ...

What is the best way to access and utilize an id within an angular component's routing system?

I am currently working on an Angular application, and this is my first experience with JS. I have a main view where I display several elements, such as movies, each of which is clickable and links to a detailed view of the movie. My question is how can I h ...

Typescript error handling: Handle 404s on all Koa routes

Issue Encountering problems while setting up Auth Controllers Difficulty using Bcrypt and JWT for encryption All POST Calls to Koa resulting in 404 errors Calls to other routes are functioning correctly Potential issue with the scope of the code. impo ...

A versatile generic type infused with dynamic typing and optional parameter flexibility

Looking to develop a function that can accept an optional errorCallback parameter. In cases where the consumer of this function does not provide a callback, I aim to default to a preset handler. The key criteria here are strong typing and utilizing the ret ...

`Developing reusable TypeScript code for both Node.js and Vue.js`

I'm struggling to figure out the solution for my current setup. Here are the details: Node.js 16.1.x Vue.js 3.x TypeScript 4.2.4 This is how my directory structure looks: Root (Node.js server) shared MySharedFile.ts ui (Vue.js code) MySharedFi ...

What methods can be used to display data using TypeScript's Optional Chaining feature?

I came across this Try it Yourself TypeScript Optional Chaining example in W3Schools TypeScript Null & Undefined section, and I have attached a screenshot for reference. https://i.sstatic.net/s8q1J.png The example demonstrates that when data is undef ...

Iterating through elements within the ng-content directive in Angular using *ngFor

Is it possible to iterate through specific elements in ng-content and assign a different CSS class to each element? Currently, I am passing a parameter to enumerate child elements, but I would like to achieve this without using numbers. Here is an example ...

A TypeScript object with user-defined keys

I have a question about utilizing TypeScript records with a custom Type as keys. Essentially, I have a specific type (a limited set of strings) that I want to use as keys for my record. My goal is to start with an empty initialization of this record. type ...

Managing the browser's "back" button functionality in React

I am currently using "react-dom-router v6.3.0" (strictly!) and I am struggling to figure out how to manage the browser's "back" button functionality. Specifically, I want to be able to detect when the user clicks the back button so that I can display ...

Incorporating a JavaScript npm module within a TypeScript webpack application

I am interested in incorporating the cesium-navigation JavaScript package into my project. The package can be installed via npm and node. However, my project utilizes webpack and TypeScript instead of plain JavaScript. Unfortunately, the package is not fou ...