Creating a data structure that filters out specific classes when returning an object

Consider the following scenario:

class MyClass {}
class MyOtherClass { something!: number; }

type HasClasses = {
    foo: MyClass;
    bar: string;
    doo: MyClass;
    coo: {x: string;};
    boo: MyOtherClass;
};

type RemovedClasses = RemoveClassTypes<HasClasses>;

I am aiming for RemovedClasses to be equal to

{ bar: string; coo: {x: string;} }
. How can this objective be achieved?

Previous attempts were made but unfortunately didn't yield the desired outcome:

type ClassesKeys<T> = {
  [P in keyof T]: T[P] extends new () => any ? P : never;
}[keyof T]

type RemoveClassTypes<T> = Omit<T, ClassesKeys<T>>;

Answer №1

It seems like you are interested in removing properties from a type based on their relation to classes, while keeping non-class object types. In your example, you remove foo and doo (both of type MyClass) as well as boo of type MyOtherClass, but retain coo of type {x: string;}.

Unfortunately, achieving this might not be possible.

TypeScript's type system is primarily structural, focusing on the shape of objects rather than their names. The distinction between objects created via different methods (new X() or Object.create() or literals) is not significant at the type level or even in runtime JavaScript. What matters most are the properties and methods an object possesses; its shape.

Consider the following comparison:

class Example {
    something: string;
    constructor(s: string) {
        this.something = s;
    }
    method(): void {
    }
}

let ex1 = new Example("ex1");
let ex2 = {
    something: "ex2",
    method(): void {
    }
};

From a typing standpoint, there is no practical difference between ex1 and ex2, despite minor runtime distinctions. Now, if we introduce these declarations:

let ex3: Example;
let ex4: { something: string; method(): void; };

All of the following assignments are valid:

ex3 = ex1;  
ex3 = ex2;  
ex4 = ex1;  
ex4 = ex2;  
ex1 = ex4;  
ex2 = ex4;  

These types are all compatible with each other, regardless of how they were defined.

While it may seem tempting to utilize the inherited constructor property of class objects for differentiation, this approach does not yield reliable results. Even objects initialized through literals can have an inherited constructor property. Therefore, achieving your desired outcome may not be feasible in TypeScript.

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

Dealing with throwing Exceptions in jest: A guide for developers

I have developed a method that throws an exception when the provided password does not match a regex pattern. I attempted to handle this in Jest. it('Should prevent insertion of a new user if the password doesn't match the regex', async () ...

Issue encountered when attempting to save items in the browser's local storage

I'm encountering an issue: ERROR Error: Uncaught (in promise): DataCloneError: Failed to execute 'put' on 'IDBObjectStore': Position object could not be cloned. Error: Failed to execute 'put' on 'IDBObjectStore& ...

The attribute 'disabled' is originally defined as a characteristic within the class 'CanColor & CanDisableRipple & HasTabIndex & MatChipBase'. However, it is replaced in the current context of 'MatChip' as an attribute

After updating my Angular version from 9.1 to 11, I encountered a compilation error. Error: node_modules/@angular/material/chips/chips.d.ts:120:9 - error TS2611:'disabled' is defined as a property in class 'CanColor & CanDisableRipple &a ...

Encountering issues when trying to build a Nestjs app with node-crc (rust cargo) in Docker

I am encountering an issue with building my Nest.js app using Docker due to a dependency called "node-crc" version "2.0.13" that fails during the docker build process. Here is my Dockerfile: FROM node:17.3.1-alpine RUN curl https://sh.rustup.rs -sSf | sh ...

The module 'contentlayer/generated' or its type declarations are missing and cannot be located

Currently running NextJS 13.3 in my application directory and attempting to implement contentlayer for serving my mdx files. tsconfig.json { "compilerOptions": { ... "baseUrl": ".", "paths" ...

Encountering a Problem with vue-check-view Library in Typescript

After successfully declaring the js plugin with *.d.ts, I encountered an issue where my view was blank after using .use(checkView). Does the library vue-check-view support Typescript? Error: Uncaught TypeError: Cannot read property '$isServer' o ...

The 'cookies' property is not defined in the 'undefined' type

I am working on incorporating Google's Sign-In for Cypress tests using the following plugin: https://github.com/lirantal/cypress-social-logins/ (I am utilizing TypeScript). The code I have implemented is as follows: it('Login through Google&apos ...

Adjust the selected value in real-time using TypeScript

Hey there, I've got a piece of code that needs some tweaking: <div> <div *ngIf="!showInfo"> <div> <br> <table style="border: 0px; display: table; margin-right: auto; margin-left: auto; width: 155%;"& ...

What is causing this TypeScript error to be raised by this statement?

Can you explain why the following statement is throwing a type error? const x: Chat = { ...doc.data(), id: doc.id } The error message states: Type '{ id: string; }' is missing the following properties from type 'Chat': message, name, ...

What are the best practices for preventing risky assignments between Ref<string> and Ref<string | undefined>?

Is there a way in Typescript to prevent assigning a Ref<string> to Ref<string | undefined> when using Vue's ref function to create typed Ref objects? Example When trying to assign undefined to a Ref<string>, an error is expected: co ...

Retrieve all exports from a module within a single file using Typescript/Javascript ES6 through programmatic means

I aim to extract the types of all module exports by iterating through them. I believe that this information should be accessible during compile time export const a = 123; export const b = 321; // Is there a way to achieve something similar in TypeScript/ ...

Error in TypeScript React: 'Display' property is not compatible with index signature

My design page in React with TypeScript template is using Material UI, with custom styles implemented using the sx prop of Material UI. To customize the styling, I have created a separate object for the properties related to the sx props: const myStyles = ...

The modal popup will be triggered by various button clicks, each displaying slightly different data within the popup

As a newcomer to Angular 4, I have encountered an interesting challenge. Currently, my code consists of two separate components for two different modals triggered by two different button clicks (Add User and Edit User). However, I now face the requiremen ...

Component in Next.js fetching data from an external API

I am attempting to generate cards dynamically with content fetched from an API. Unfortunately, I have been unsuccessful in finding a method that works during website rendering. My goal is to pass the "packages" as properties to the component within the div ...

When object signatures match exactly, TypeScript issues a warning

I am facing an issue with typescript while trying to use my own custom type from express' types. When I attempt to pass 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>' as a parameter of type 'Context&a ...

Utilizing ag-grid with Vue.js: Implementing TypeScript to access parent grid methods within a renderer

I've integrated ag-grid into my project and added a custom cell renderer: https://www.ag-grid.com/javascript-grid-cell-rendering-components/#example-rendering-using-vuejs-components Although the renderer is working well, I'm facing an issue whe ...

PhpStorm flawlessly detects ES7 type hinting errors

For my project, I have implemented TypeScript. While JavaScript's array includes() function has been valid since ECMA6, setting the lib parameter in tsconfig to "es6" results in a non-fatal error being thrown in the browser console when using the foll ...

A guide on how to identify the return type of a callback function in TypeScript

Looking at this function I've created function computedLastOf<T>(cb: () => T[]) : Readonly<Ref<T | undefined>> { return computed(() => { const collection = cb(); return collection[collection.length - 1]; }); } Thi ...

Dispersed data points within ng2-charts

After reviewing the ng2-charts documentation at , unfortunately, I did not come across any information regarding a Scattered Plot. Are there alternative methods to create a Scattered plot chart in ng2-charts? Any helpful tricks or customization options a ...

Angular 6's subscribe method is causing the UI to not update

I'm currently facing an issue where my component does not refresh the UI after I input data. I always have to manually refresh the page to see the changes. I suspect there might be a problem with the .subscribe method in Angular 6. Previously, when I ...