How to assign a new type to a class in Typescript

I am attempting to re-export a class with an internal type declaration in Typescript. My goal is for the re-exported class to be usable both as a class (with new) and as a type. Below is an example of what I have tried:

class XReal { foo() {return 5} }
declare class XFake { bar(): number }
export const XExport = (XReal as any) as typeof XFake

declare const c: XExport;
const ci = new XExport;

While I can use new XExport, I am unable to use XExport as a type.

Is there a way to alias XReal as XExport but maintain the type

XFake</code, allowing me to utilize <code>XExport
as both a type and a class constructor?

Answer №1

In TypeScript, types and values operate in distinct namespaces. It is possible to have a type named Foo and an unrelated value also named Foo. The compiler does not get confused because they are different entities that exist in separate contexts:

const Foo = "abc"; // <-- value named Foo
interface Foo { x: number; } // <-- type named Foo

const x = Foo; // <-- this represents the value
// const x: "abc";

const y: Foo = { x: 123 }; // <-- this represents the type

type Z = typeof Foo; // <-- this refers to the value, while Z is a type
// type Z = "abc"

This concept might be perplexing for someone whose first language is not TypeScript, but the compiler can differentiate between names referencing types versus values based on the context. Much like how native English speakers can understand sentences like "My cousin Virginia lives in Georgia" and "My cousin Georgia lives in Virginia" by interpreting the context of person versus location.

There is no necessary connection between a type and a value with the same name.


When it comes to declarations such as interface and type, they define a named type while variable declarations using let and const define a named value. Additionally, class declarations are unique because they declare both a type and a value under the same name. The type corresponds to an instance of the class, whereas the value represents the class constructor:

class Bar { a = 1; }

const b: Bar = new Bar();
// ----> ^^^       ^^^ <---
// instance type        constructor value

const baz = Bar; // <-- constructor value
// const baz: typeof Bar 

Thus, although there isn't a mandatory relationship between types and values with identical names, those stemming from class declarations will exhibit a connection where the named value serves as a constructor for the named type. Individuals often mistakenly assume this common relationship is required, leading them to write typeof X to reference a potentially non-existent constructor for instances of X. Hopefully, this explanation prevents you from making this error in the future.


If you aim to replicate the effects of a class declaration without actually utilizing one, allowing people to pretend it was declared in that manner, you must establish a suitable named type (via interface or type) along with an appropriate named value (using let or const). In your scenario, it would look something like this:

declare class XFake { bar(): number }
export type XExport = XFake; // named type    
export const XExport = (XReal as any) as typeof XFake // named value

Remember, you might not even require the XFake declaration since you can directly specify the instance and constructor:

export type XExport = { bar(): number };
export const XExport = (XReal as any) as new () => XExport

This approach enhances user experience, particularly within IntelliSense, where references will mention XExport instead of

XFake</code. This makes <code>XExport
appear more like a "regular" class:

declare const c: XExport;
// const c: XExport
const ci = new XExport;
// const ci: XExport

Playground link to code

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

Every time I attempt to install a package, I encounter an NPM unmet peer dependency issue

Entering the complex world of NPM for the first time has been quite a challenge. After running create-react-app, the installation process is almost complete except for some warning messages: yarn add v1.17.3 [1/4] Resolving packages... warning react-scri ...

Unexpected artifacts are being introduced to the build folder by the compiler

Currently, I am following the steps outlined in this Getting Started guide to set up the installation of tsoa. According to their instructions, I have created a routes.ts folder and placed it under /build: /build /routes.ts Next, in /src/app.tsx, I mak ...

Mastering the art of utilizing GSI Index and FilterExpression in AWS DynamoDB querying

In my DynamoDB database table, I have the following structure. It consists of a primary key (ID) and a sort key (receivedTime). ID(primary key) receivedTime(sort key) Data ID1 1670739188 3 ID2 167072 ...

I have attempted numerous methods, but the TypeScript object remains potentially undefined

My current code involves using canvas to capture the cropped image. Below is the function that handles this process: export const getCroppedImg = ( image: HTMLImageElement, crop: Crop, fileName: string ): Promise<Blob> => { let canvas: HTM ...

React error: The module "react-router-dom" does not have a member named "useNavigate" available for export

I'm attempting to include useNavigate for use as outlined in the top answer here: react button onClick redirect page import { useNavigate } from "react-router-dom"; However, I am encountering this error: export 'useNavigate' (impo ...

After running a yarn build on a TypeScript project using a .projenrc.js file, make sure to include any packaged or additional text files in the lib folder, rather

After utilizing projen to create my typescript project, I followed these steps: mkdir my-project, git init, and npx projen new typescript. Additionally, I created two files - sample.txt and sample.js, along with the default file index.ts within the folder ...

How to set the default option in a select dropdown using Angular and Types

It's been a while since I last worked with Angular and now I'm tasked with working on an existing system. I introduced an NgModal dialog to send text messages, designed as shown here: https://i.sstatic.net/67U1M.png Below is the code snippet I ...

Is there a way to selectively transfer attributes and behaviors from an interface to a fresh object in typescript?

Is there a way in javascript to selectively copy properties from one object to another? I am familiar with using Object.assign() for this purpose. Specifically, I am looking to extract only the properties defined within the following interface: export in ...

Creating a function that is accessible to the entire module

Creating a universal function in a file that is not a module: example.ts: function example() {} You can easily call this function from another file, say test.ts, without needing to import the function from example.ts: test.ts: example(); // calling univ ...

Unable to load content from Three.js Examples library (Error loading script for "three/examples/jsm/loaders/OBJLoader2")

In my Angular application, I have a simple setup using Three.js. When I try to import the `OBJLoader2` from `three/examples/jsm/loaders/OBJLoader2`, everything works fine except when running it with the `ts_devserver`. The browser console shows an error: G ...

Tips for efficiently passing TypeScript constants to Vue templates without triggering excessive reactivity

I'm curious about the most efficient way to pass a constant value to a template. Currently, I am using the data property in Vue, but I believe that is better suited for state that changes over time as Vue adds event listeners to data properties. The c ...

Struggling with getting render props to work in Next.js version 13

Looking to develop a custom component for Contentful's next 13 live preview feature in the app directory, I thought of creating a client component that can accept a data prop and ensure type safety by allowing a generic type to be passed down. Here is ...

What is the process for sending an HTTP post request with a React/Typescript frontend and a C#/.Net backend?

In the frontend code, there is a user login form that accepts the strings email and password. Using MobX State Management in the userstore, there is an action triggered when the user clicks the login button to submit the strings via HTTP post. @action logi ...

Typescript, left untranspiled in Karma test runs

I am attempting to conduct karma tests against Typescript. I have successfully installed karma and can run tests, but encounter Syntax Errors when my *.ts files contain Typescript syntax like this: Error: (SystemJS) SyntaxError: Unexpected token ) It s ...

There was an error while trying to read the properties of undefined (specifically the state). Make sure to include this.state.a

I am struggling with an error that I have never encountered before. Despite having experience working with functional components, I am new to class components. I used create react app to install the application, but it seems like I might be missing a req ...

Finding the index of a chosen option in Angular

Attempting to retrieve the index of the selected option from a select element using Angular. The Angular (4) and Ionic 3 frameworks are being utilized. The template structure is as follows: <ion-select [(ngModel)]="obj.city"> <ion-option ...

Using MobX to alter observed observable values outside of actions is not permitted in combination with Ant Design components

When trying to upload files to the server and receive a response, I encountered an issue. If I override the onChange property of the Upload component (from antd), mobx starts throwing errors and the file uploading process gets stuck in the 'uploading& ...

The preflight request for Ionic 7 fails the access control check, even though all origins, methods, and headers are permitted

Snippet; this.http.post(this.endpoint + "api/auth/signin", {"username": handle, "password": password}).subscribe(res => { // @ts-ignore if (res["status"] === "authorized") { loc ...

Resolving TS2304 error using Webpack 2 and Angular 2

I have been closely following the angular documentation regarding webpack 2 integration with angular 2. My code can be found on GitHub here, and it is configured using the webpack.dev.js setup. When attempting to run the development build using npm start ...

Different Angular 2 components are resolved by routes

Consider this scenario: Upon navigating to the URL /product/123, the goal is to display the ProductComponent. This is how it's currently configured: RouterModule.forRoot([ { path: 'product/:productId', ...