Can the 'this' keyword be used to declare the type in TypeScript in this manner?

For instance:

// ===== Declaration ===== //
class A {
  CONSTANTS_TYPE: { [key: string]: [any] }
  CONSTANTS: { [key in keyof this['CONSTANTS_TYPE']]: key }
  bar<T extends keyof this['CONSTANTS_TYPE'] | string>(
    type: T,
    callback: (...args: T extends keyof this['CONSTANTS_TYPE'] ? this['CONSTANTS_TYPE'][T] : any) => any
  ) { /** some implementation*/ }
}
class B extends A {
  CONSTANTS_TYPE: {
    aa: [number],
    bb: [string]
  }
  // Issue Here
  // Type '{ aa: "aa"; bb: "bb"; }' is not assignable to type '{ [key in keyof this["CONSTANTS_TYPE"]]: key; }'.(2322)
  CONSTANTS: { [key in keyof this['CONSTANTS_TYPE']]: key } = {
    aa: 'aa',
    bb: 'bb'
  }
}

// ===== Call ===== //
const b = new B;
b.bar(b.CONSTANTS.aa, (arg) => {
  // so I can determine if 'arg' is of type 'number'
  arg // number type
});

it's functional, but not ideal.

I am aware that '// @ts-ignore' would provide a quick fix

however, I believe there might be alternative solutions

[Playground Link]

Answer №1

It appears that there are some issues with the code you have written:

  • Avoid using @ts-ignore as much as possible.
  • The value aa: 'aa' is not a number and should have resulted in an error, but it didn't due to the way it was implemented.
  • In ...args: T, T represents an array rather than a single parameter.
  • Questioning the use of ...args in the foo function.

Here is a potential solution for you:

// ===== Declaration ===== //
type ValueOf<T> = T[keyof T];

abstract class A {
  abstract CONSTS: { [key: string]: any }

  foo<T extends ValueOf<this['CONSTS']>>(
    type: T,
    callback: (arg: T) => any
  ) { /** some implementation*/ }
}

class B extends A {
  CONSTS: {
    aa: number,
    bb: string
  } = {
    aa: 5,
    bb: 'bb'
  }
}

// ===== Call ===== //
const b = new B;
b.foo(b.CONSTS.bb, (arg) => {
  // When this code runs, 'arg' will be recognized as 'string' type
  arg // string type
});

typescript playground

Answer №2

Wouldn't a specialized class be more suitable for your needs?

declare class Bar<E extends Record<string, [any]>> {
  CONST_TYPES: E;
  CONSTANTS: {
    [M in keyof E]: M
  }

  constructor(types: E);

  bar<V extends keyof E>(type: V, callback: (value: E[V]) => any): any;
}

const bar = new Bar({ aa: [42], bb: ['foo'] });

bar.bar(bar.CONSTANTS.bb, (argument) => {
  argument // [string]
})

Answer №3

Finally, after much searching, I have discovered a solution.

// ===== Declaration ===== //
class A<T extends Record<string, [any?]>> {

    foo<U extends keyof T | string>(
        type: U,
        callback: (...args: U extends keyof T ? T[U] : any) => any
    ) { /** some implementation*/ }
}

type T_BConstsType = {
    aa: [number],
    bb: [string]
}

class B extends A<T_BConstsType> {

    CONSTS: { [key in keyof T_BConstsType]: key } = {
        aa: 'aa',
        bb: 'bb'
    }
}

// ===== Call ===== //
const b = new B;
b.foo(b.CONSTS.aa, (arg) => {
    // Now I can determine that 'arg' is of type 'number'
    arg // number type
});

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

Comprehending the concepts of Observables, Promises, using "this" keyword, and transferring data within Angular with TypeScript

I am trying to figure out why I keep receiving the error message: "Uncaught (in promise): TypeError: this.dealership is undefined" when working with the authentication.service.ts file. export class AuthenticationService { private currentUserSubject: ...

Having trouble with clearInterval in my Angular code

After all files have finished running, the array this.currentlyRunning is emptied and its length becomes zero. if(numberOfFiles === 0) { clearInterval(this.repeat); } I conducted a test using console.log and found that even though ...

Error: Trying to access the 'blogpost' property of an undefined variable results in a TypeError while executing the NPM RUN BUILD command in Next.js

Encountering a frustrating issue while trying to run my Next.js application for production build. The problem seems to be related to the "blogpost" parameter in the following codeblock: import React from "react"; import Slab from "../../comp ...

Invalid file name detected during the download process

Below is the Javascript code I currently use to download a pdf: var link = document.createElement('a'); link.innerHTML = 'Download PDF file'; link.download = "Report.pdf"; link.href = 'data:application/octet-stream;base64 ...

How can I change a ReactNode into a text format?

I am looking for a way to convert the following code snippet into a string while preserving Tailwind CSS and other elements. My project uses Next.js with TypeScript and Tailwind CSS. Input : export default function Header_1() { return ( <div clas ...

The module "@clerk/nextjs/server" does not contain a member with the name "clerkMiddleware" available for export

Currently, I am working on Nextjs 14 with typescript and implementing authentication and authorization using Clerk. Following the instructions in the Clerk documentation, I included the code snippet below in my middleware.ts file: import { authMiddleware } ...

What is the best way to retrieve an array that was created using the useEffect hook in React?

Utilizing the power of useEffect, I am fetching data from two different APIs to build an array. My goal is to access this array outside of useEffect and utilize it in the return statement below to render points on a map. However, when trying to access it ...

Using [(ngModel)] in Angular does not capture changes made to input values by JavaScript

I have developed a custom input called formControl, which requires me to fetch and set its value using [(ngModel)]: import { Component, Injector, OnInit, forwardRef } from '@angular/core'; import { ControlValueAccessor, FormControl, NG_VALUE_ACCE ...

Can the arrow function properly subscribe to an Observable in Angular and what is the accurate way to interpret it?

I'm currently working through the official Angular tutorial: https://angular.io/tutorial/toh-pt4 Within this tutorial, there is a component class that subscribes to a service: import { Component, OnInit } from '@angular/core'; import { He ...

An error occurred while attempting to set up Next-auth in the process of developing

In my Next.js app, I have implemented next-auth for authentication. During local development, everything works fine with 'npm install' and 'npm run dev', but when I try to build the project, I encounter this error message: ./node_modul ...

The error message "Property 'originalUrl' is not found in type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'" appeared

In my TypeScript project, I am utilizing a gulpfile to initiate the process. Within the gulpfile, I am using express where I encounter an issue while trying to access req.originalUrl, with req being the request object. An error is thrown stating Property ...

The Karma ng test fails to display any build errors on the console

I've encountered a frustrating issue while working with Karma and Jasmine for testing in my Angular 7 project. The problem arises when there are errors present in the .spec.ts or .ts files, as running ng test does not display these errors in the conso ...

Detecting Typescript linting issues in VSCode using Yarn version 3.2.3

Every time I try to set up a new react or next app using the latest yarn v3.2.3, my VS Code keeps showing linting errors as seen in the screenshot below. The main error it displays is ts(2307), which says Cannot find module 'next' or its correspo ...

Creating an Angular project that functions as a library and integrating it into a JavaScript project: a step-by-step guide

Is it feasible to create an Angular library and integrate it into a JavaScript project in a similar manner as depicted in the image below? The project structure shows trading-vue.min.js being used as an Angular library. Can this be done this way or is th ...

Unable to exclude folder while creating production build is not functioning as intended

I've got a directory full of simulated data in the "src/api/mock" folder, complete with ts and JSON files. I'm attempting to have Webpack skip over them during the production build process. I attempted to implement the following rule, but unfortu ...

Which is the optimal choice: subscribing from within a subscription or incorporating rxjs concat with tap?

After storing data in the backend, I proceed to retrieve all reserved data for that specific item. It is crucial that the data retrieval happens only after the reservation process to ensure its inclusion. Presented with two possible solutions, I am cont ...

Angular2 Directive that Duplicates a Group of <tr> Elements

How can I build a component that generates HTML based on this data and HTML code? The <head> and <tbody> sections are projected, and I understand how to project multiple elements. However, I am unsure of how to repeat the projected <tr> i ...

Executing npm and ng commands via an Ant script on a Windows machine leads to the error message "The specified file could not be found."

When attempting to execute the following Ant script, which runs the "npm" command: <target name ="test"> <exec executable="npm" failonerror="true"> <arg value="install" /> </exec> </target> An error occurs, i ...

What could be the root of this next.js build issue occurring on the Vercel platform?

I recently upgraded my next.js project to version 12.0.7, along with Typescript (4.5.4) and pdfjs-dist (2.11.228), among other libraries. Locally, everything runs smoothly with the commands yarn dev for development and yarn build for building. However, af ...

Timeout with Promise

I'm looking to enhance my understanding of working with promises by rewriting this function to resolve the promise instead of resorting to calling the callback function. export const connect = (callback: CallableFunction|void): void => { LOG.d ...