How can you choose the attributes of an object that are not considered as keys of a specific type?

Imagine a scenario where...

type Thing = {
    name: string;
    // other characteristics
};

...and there is an instance that appears as follows...

const obj = {
    name: 'blah',
    // other properties similar to those in Thing
    someProp: true,
    otherProp: 123,
    yetAnotherProp: 'yay',
};

...the objective is to filter out the properties in obj that are not present in Thing, resulting in:

const objWithoutThing = {
    // none of the properties from `Thing`
    someProp: true,
    otherProp: 123,
    yetAnotherProp: 'yay',
};

For example:

const objWithoutThing = Object
    .keys(obj)
    .filter(key => key not in keyof Thing) // this syntax doesn't work, what should be used here?
    .reduce((o, key) => ({ ...o, [key]: obj[key] }), {});

// now `objWithoutThing` includes all properties from `obj` except those defined in `Thing`

Answer №1

There is no automatic way to achieve this. When TypeScript code is transpiled to JavaScript, the static type system and type aliases like Thing get erased. Consequently, at runtime, there won't be any information available to omit keys from obj based on Thing.


To exclude keys of Thing during runtime, you must explicitly define a list of such keys as a value that remains present at runtime. By putting in some effort, you can make the compiler check if the list is created correctly:

const thingKeys = ["name"] as const;

type ThingKeysCheck<
    T extends typeof thingKeys[number] = keyof Thing,
    U extends keyof Thing = typeof thingKeys[number]
    > = void;

The use of const assertion ensures that the compiler recognizes thingKeys contains the string literal "name". Without it, thingKeys would simply be seen as an array of strings.

ThingKeysCheck serves as a validation to confirm the consistency between the string literals in thingKeys and keyof Thing. Any errors will indicate missing or extra keys in either object.


Once you have defined thingKeys, you can apply it in your filter logic. The function withoutThing() uses a generic signature to ensure that passing an object T assignable to

Thing</code results in a return type of <code>Omit<T, keyof Thing>
using the utility type Omit<T, K>:

function withoutThing<T extends Thing>(obj: T): Omit<T, keyof Thing> {
    return Object
        .keys(obj)
        .filter(k => !(thingKeys as readonly string[]).includes(k))
        .reduce<any>((o, k) => ({ ...o, [k]: obj[k as keyof Thing] }), {});
}

Several type assertions are used within the function implementation to address compiler warnings about creating a valid object of type Omit<T, keyof Thing>. Overall, it maintains similar functionality to your original implementation.


Let's test its functionality:

const objWithoutThing = withoutThing(obj);
console.log(objWithoutThing.someProp); // true
console.log(objWithoutThing.otherProp.toFixed(2)); // 123.00
console.log(objWithoutThing.yetAnotherProp.toUpperCase()); // "YAY"
console.log(objWithoutThing.name); // undefined
// -----------------------> ~~~~
// Property 'name' does not exist

Seems to be working well.


Playground link containing the code

Answer №2

If you're working with TypeScript version 3.5 or higher, you have the option to utilize Omit

type Person = {
    name: string;
    age: number;
    occupation: string;
}

type Employee = {
    name: string;
}

type PersonWithoutEmployee = Omit<Person, keyof Employee>;

const personWithoutEmployee: PersonWithoutEmployee = {
    // no properties from `Employee`
    age: 30,
    occupation: 'developer',
};

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

Angular Error: Trying to access a property on an undefined variable

I'm currently having an issue with assigning data from an API to my Angular component file. Whenever I try to assign the data to my object variable, I receive an error stating: "cannot set property of undefined." Below is the relevant code snippet: C ...

Steer clear of duplicating template literal type entries when dealing with optional routes

My code includes a type called ExtractParams that extracts parameters from a URL string: type ExtractParams<Path extends string> = Path extends `${infer Start}(${infer Rest})` ? ExtractParams<Start> & Partial<ExtractParams<Rest>& ...

Substituting generic type in inherited class method results in error message: "Property 'x' in type 'y' cannot be assigned to the property with the same name in the base class 'Parent'."

Here is the code snippet I am working with: class BaseModel { protected getAttribute<T extends BaseModel>(): keyof T | null { return null; } } class Payment extends BaseModel {} class Item extends BaseModel {} class Sale extends BaseModel { ...

Tips on how to properly handle Promises in a constructor function

My Angular Service is currently making http requests, but I am looking to retrieve headers for these requests from a Promise. The current setup involves converting the promise to an Observable: export class SomeService { constructor(private http: HttpCl ...

Customizing key values within nested objects in Angular2: A comprehensive guide

I need assistance with setting up a JSON object for a post in Angular2/Typescript. I am trying to dynamically set the nested object values for a key. Is it possible to achieve this using Angular2/Typescript? I have attempted to retrieve the values from JS ...

Update button Image upon click

Is there a way to swap the image on a button when it's clicked? I want my button to start with one icon, but then change to another icon once it has been clicked. How can I achieve this effect? Any suggestions on how to make this happen? Check out ...

Utilizing various settings using `.env` files in NodeJs

As I work on building a backend in nodejs, one of the key considerations is how to incorporate an environment configuration into the project. I am envisioning a structure where there is a /config folder housing my envparser.ts (still brainstorming a catchi ...

Ways to determine the types of props received by a function when the arguments vary for each scenario?

I have a specialized component that handles the majority of tasks for a specific operation. This component needs to invoke the onSubmit function received through props, depending on the type of the calling component. Below is an example code snippet show ...

Is it possible that jest is unable to catch the exception?

I have a simple function that looks like this: function foo({ platform }) { if (platform === 'all') { throw new Error('Platform value can only be android or ios'); } return `${platform}`; } After writing unit tests, the re ...

Ways to prevent Deno Workers from using cached source code

Good day, I am currently working on building a custom javascript code execution platform using Deno Workers. Additionally, I have implemented an Oak web server to manage requests for script modifications and their compilation and execution. An issue arise ...

I'm curious if anyone has experimented with implementing TypeScript enums within AngularJS HTML pages

During my Typescript project, I defined an enum like this: enum Action { None = 0, Registering = 1, Authenticating = 2 }; In the controller, I declared a property named action as follows: class AuthService implements IAuthService { action: number; ...

What steps do I need to take in order to set up InfluxDB with Nest

As a beginner in the world of software development, I am eager to expand my knowledge and skills. Has anyone had experience operating influxdb with nestjs? If so, I would greatly appreciate it if you could share your past experiences. Thank you for takin ...

Using TypeScript with async await operators, promises, and the memoization pattern

I am currently in the process of updating my code to incorporate the latest TypeScript enhancements. We have implemented various memoization patterns, with the main goal being to ensure that services with multiple subscribers wait for one call and do not t ...

The production build encountered an issue as it was anticipating 3 arguments, however, it only received

import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'elipsis' }) export class ElipsisPipe implements PipeTransform { transform(text, length, clamp) { text = text || ''; clamp = clamp || '...& ...

Definition of DataTypes in TypeScript

My goal seems simple to me, but I am realizing that my experience with Typescript might not be enough. I want to create a type that can accept the following expressions: const dp: DataPoint = [1, 2]; const dp2: DataPoint = [1, 2, 3]; const dps: DataPoints ...

`Incorporate concurrent network requests in React for improved performance`

I am looking to fetch time-series data from a rest service, and currently my implementation looks like this async function getTimeSeriesQuery(i) { // Demonstrating the usage of gql appollo.query(getChunkQueryOptions(i)) } var promises = [] for(var i ...

Determine whether a response is not received within 8 seconds

One of the methods in my Angular component is responsible for returning data Here is a snippet of that method getRecognitionById() { this.loaderService.show(null, true); forkJoin( this.vendorWebApiService.getRecognitionById(this.executiveCh ...

Is there an improved method for designing a schema?

Having 4 schemas in this example, namely Picture, Video, and Game, where each can have multiple Download instances. While this setup works well when searching downloads from the invoker side (Picture, Video, and Game), it becomes messy with multiple tables ...

In TypeScript, specifying that a type should only extend from an object does not effectively prevent strings from being accepted

My goal is to ensure proper typing for an attributes object that is stored in a wrapper class. This is necessary to maintain correct typing when accessing or setting individual attributes using the getOne/setOne methods as shown below. However, I am facin ...

Unable to locate youtube.ts file in the Angular 2 project for the YoutubeAPI integration

I've been using a youtube.d.ts file from the DefinitelyTyped project. It functions perfectly in my WebStorm while I'm editing, but once I try to run it, I encounter a 404 error stating that typings/youtube.js is not found. This file doesn't ...