Contrast between employing typeof for a type parameter in a generic function and not using it

Can you explain the difference between using

InstanceType<typeof UserManager>

and

InstanceType<UserManager>

I'm trying to understand TypeScript better. I noticed in TS' typeof documentation that

SomeGeneric<typeof UserManager>
is mentioned as a more general typing. Does this mean we can simplify typeof UserManager to something like Function, making it essentially InstanceType<Function>?

Answer №1

When discussing classes, it’s important to note that they function as both values (the class constructor) and types.

So, if the value is represented by UserManager as the class constructor, then typeof UserManager delineates the type associated with that constructor. This type is used in conjunction with the new keyword and includes static methods.

The type, on the other hand, exemplified by UserManager, serves as the interface for instances.

The purpose of InstanceType<T> is to identify the type of instances generated by a given constructor T. For this reason, T must be a constructor type to maintain validity. Otherwise, you’ll encounter a type error:

type A = InstanceType<UserManager>
// Type 'UserManager' does not satisfy the constraint 'abstract new (...args: any) => any'.
//  Type 'UserManager' provides no match for the signature 'new (...args: any): any'.(2344)

This elucidates that the type:

InstanceType<typeof UserManager>

Is essentially indistinguishable from:

UserManager

Why can't we use a class as the type instead of needing to extract the type using typeof?

There's actually no requirement to do so unless solely possessing the type of a constructor. In the example shared, you can simply proceed with:

const user: UserManager = {
  name: "John",
  surname: "Doe",
};

The code functions appropriately because it adheres to the interface specifications of an instance belonging to UserManager, regardless of its origin. Thus, Typescript accepts it without issue.


Update:

Referencing this playground link, triggers the following error message:

Argument of type 'typeof Child' is not assignable to parameter of
type 'Parent<{}>'. Property 'method' is missing in type
'typeof Child' but required in type 'Parent<{}>

"why is it labeled as typeof Child?"

Each value inherently adopts the type of typeof value. Consequently, when utilizing Child as a value (as demonstrated by passing it as an argument), its type automatically becomes typeof Child.

Here, the value attributed to Child represents a class constructor, essentially a callable function capable of generating instances of Child.

"How can I make this work by only providing the class Child?"

To successfully execute instance methods tied to a class, instantiation is essential. Attempting to execute .method(), an instance method, without creating an actual instance will inevitably fail.

Hence, your inquiry boils down to “How can I utilize an instance of a class sans instantiating it?” The answer is simple: you cannot.

Consider a car manufacturing facility. You cannot instruct the factory to ignite an engine; rather, you convey such instructions to a car produced by said factory. To initiate the car, you first need to construct one via the factory.

// The “factory” equivalent in this scenario
class Car {
  startEngine() {}
}
const aCar: Car = new Car() // representative of what the factory manufactures

In summary:

  • Factory (the constructor)

    • value: Car
    • type: typeof Car
  • Car (an instance)

    • value: new Car()
    • type: Car

You have the option to either create an instance prior to invoking the function:

function foo(instance: MyClass){
  instance.someMethod()
}
foo(new MyClass())

Alternatively, you could transmit the constructor information and instantiate within the function:

function foo(someClass: typeof MyClass){
  const instance = new someClass()
  instance.someMethod()
}
foo(MyClass)

Ultimately, the bottom line remains - at some point, you must assemble the car to drive the car.

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

Unveiling individual modules of an Angular library using public-api.ts in the latest version of Angular (Angular 13)

After completing an upgrade on my Angular library project from version 11 to 13, I encountered an issue when attempting to execute the ng build command. In version 11, the setup looked like this: I had multiple smaller modules, each containing various co ...

Angular 6 TypeScript allows for efficient comparison and updating of keys within arrays of objects. By leveraging this feature

arrayOne: [ { id: 1, compId: 11, active: false, }, { id: 2, compId: 22, active: false, }, { id: 3, compId: 33, active: false, }, ] arrayTwo: [ { id: 1, compId: 11, active: true, }, { id: 2, compId: 33, active: false, ...

How can you display a set of components in React using TypeScript?

I'm currently working on rendering an array of JSX Components. I've identified two possible methods to achieve this. Method one (current approach): Create the array as an object type that stores the component properties and then build the JSX co ...

Issue with React not displaying JSX when onClick Button is triggered

I've recently started learning React and I'm facing a problem that I can't seem to figure out. I have a basic button, and when it's clicked, I want to add another text or HTML element. While the console log statement is working fine, th ...

After deploying to Heroku, cal-heatmap encounters errors despite functioning correctly in a local environment

I successfully implemented a cal-heatmap instance in my Angular 2 (angular-cli) project locally, but when I deployed the project to Heroku, I encountered some errors that prevent the cal-heatmap from displaying. https://i.stack.imgur.com/8gY90.png The er ...

What is the most effective way to use a withLatestFrom within an effect when integrating a selector with props (MemoizedSelectorWithProps) sourced from the action?

I am struggling to utilize a selector with props (of type MemoizedSelectorWithProps) in an effect inside WithLatestFrom. The issue arises because the parameter for the selector (the props) is derived from the action payload, making it difficult for withLat ...

A guide on integrating a vue-concurrency Task Creator with argument support

I've been grappling with my Vue 3 / TypeScript app and the vue-concurrency library. Everything is nearly in place, but configuring a Task Creator to accept arguments has proven to be quite challenging. Following the Task Creators pattern outlined in ...

Every checkbox has been selected based on the @input value

My component has an @Input that I want to use to create an input and checkbox. import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; @Component({ selector: 'app-aside', templateUrl: './aside.component ...

deleting the existing marker before placing a new marker on the Mapbox

Upon the map loading with GeoJson data, I have implemented code to display markers at specified locations. It works flawlessly, but I am seeking a way to remove previous markers when new ones are added. What adjustments should be made for this desired func ...

The local types package cannot be built by react-scripts even though tsc has successfully completed the process

I have developed an application with a TypeScript frontend and backend. To streamline the process, I decided to create a shared types module that contains all the necessary types for both components in one centralized location. Rather than going through th ...

What is the reason behind TypeScript's lack of inference for function parameter types when they are passed to a typed function?

Check out the code snippets below: function functionA(x: string, y: number, z: SpecialType): void { } const functionWrapper: (x, y, z) => functionA(x, y, z); The parameters of functionWrapper are currently assigned the type any. Is there a way we can ...

Async function causing Next JS router to not update page

I'm diving into the world of promises and JavaScript, but I've encountered an issue while working on a registration page following a tutorial on YouTube. Currently, I am using next.js with React and TypeScript to redirect users to the home page i ...

Discovering the right category for a general component: A step-by-step guide

How about creating a new list component that can work with an array of objects? <script setup lang="ts"> const props = defineProps<{ items: Record<string, unknown>[], selected: Record<string, unknown> | null field: stri ...

What is the best way to incorporate an external .css file into my Angular project by referencing its URL?

I'm managing a collection of CSS files online and I need to incorporate each one into my project based on its specific requirements. One component in particular is connected to different numerical IDs in the router. I am looking for a way to dynamica ...

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

ERROR TS1086: A declaration of an accessor within an ambient context is not allowed. Accessor for firebaseUiConfig(): NativeFirebaseUIAuthConfig

Trying to create a Single Page Application with Angular/CLI 8. Everything was running smoothly locally until I tried to add Firebase authentication to the app. Upon compiling through Visual Studio Code, I encountered the following error message: ERROR in ...

Tips for attaching an event listener to a div element that is accessed by reference in a React and TypeScript environment

I am attempting to attach an event listener to the div element using a ref. In my code, I have added a ref called div_ref to the Wrapper div and accessed that div_ref in the enableDragEventListeners method to add event listeners to it on component mount. ...

Content obscuring dropdown menu

I am currently working on a screen design that resembles the following: return ( <SafeAreaView> <View style={styles.container}> <View style={styles.topContainer}> <View style={styles.searchFieldContainer}> ...

Eslint is actively monitoring files specified in the eslintignore to ensure they meet the set

I am currently working on a TypeScript project that is bundled by Webpack. I want to integrate Eslint into the project, but I have encountered an issue where Eslint watches compiled files even if they are listed in the .eslintignore file. .eslintignore: . ...

Combine all TypeScript enums into a single one

Looking for a way to combine two separate enums into one for easier use. export enum ActionTypes1 { ClearError = 'CLEAR_ERROR', PrependError = 'PREPEND_ERROR', } export enum ActionTypes2 { IncrementCounter = 'INCREMENT_COUNT ...