Can we determine the data type of an object based on a property within an interface?

Here is my current interface:

MyInterface {
    prop1?: string,
    prop2?: string,
}

Now, I am looking to introduce an alternative property that mirrors the content of the existing properties but also infers if any properties are defined.

For instance:

const example: MyInterface = {
    prop2: 'some value',
    alternative: {
       prop2: 'some alternative'
    }
}

// Here, alternative is inferred as {prop2: string}
const example2: MyInterface = {
    prop2: 'some value',
    alternative: {} // ERROR! prop2 should be defined
}



// Here, alternative is inferred as {prop1: string}
const example3: MyInterface = {
    prop1: 'some value',
    alternative: {
        prop2: 'this is prop 2'.
    } // ERROR! prop1 should be defined
}

Is there a way to achieve this?

I attempted using typeof this, but it was unsuccessful.

Answer №1

To derive keys, one can utilize mapped types alongside Omit, which allows for the exclusion of the alternative key:

type CustomProp<T> = {
  [K in keyof T]: T[K];
} & {
  alternative: Omit<CustomProp<T>, 'alternative'>;
}

type B = {
  prop2: number
}

const b: CustomProp<B> = {
  prop2: 123,
  alternative: {
    prop2: 456
  }
}

Answer №2

Perhaps a potential solution is presented here, although 1) I am unable to replicate your final scenario, and honestly cannot fathom its consistency; and, 2) I found it necessary to introduce an additional interface.

The methodology in this instance differs from yours, as the shape of alternative dictates the acceptable form of the outer object: this is due to the specificity of the construction (specific nesting which remains unchanged), and the parameterization on M, representing the type of alternative rather than the outer object. This approach presents logical uncertainty prompting further investigation and possible restructuring.

interface MyInterface {
  prop1?: string;
  prop2?: string;
}

type MyAltInterface<M extends MyInterface> = M & {
  alternative: M;
};

function MyAltInterface<M extends MyInterface>(spec: MyAltInterface<M>): MyAltInterface<M> {
  return spec;
}

// alternative is { prop1: string; }
const example1 = MyAltInterface({
  prop1: 'some value',
  alternative: {
    prop1: 'some alternative'
  }
});

// alternative is {}
const example2 = MyAltInterface({
  prop2: 'some value',  // ERROR: 'prop2' does not exist in alternative
  alternative: {}
});

// alternative is { prop2: string; }
const example3 = MyAltInterface({
  prop1: 'some value',  // ERROR: 'prop1' does not exist in alternative
  alternative: {
    prop2: 'this is prop 2'
  }
});

// alternative is { prop1: string; prop2: string; }
const example4 = MyAltInterface({  // ERROR: 'prop2' is missing
  prop1: 'some value',
  alternative: {
    prop1: 'this is prop 2',
    prop2: 'this is prop 2'
  }
});

Link to 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

Today is a day for coming together, not for waiting long periods of

When grouping by month and dealing with different days, I encountered an issue similar to the one shown in this image. https://i.stack.imgur.com/HwwC5.png This is a snapshot of my demo code available on stackblitz app.component.html <div *ngFor="let ...

Guide for specifying type when passing a component as a prop

Struggling to successfully pass a component as a prop to a straightforward functional component called RenderRoute: interface RouteProps { component: React.ComponentType; isProtected: boolean; isLoggedIn: boolean; path?: string; exact?: boolean; ...

The concept of ExpectedConditions appears to be non-existent within the context of

Just starting out with protractor and currently using version 4.0.2 However, I encountered an error with the protractor keyword when implementing the following code: import { browser } from 'protractor/globals'; let EC = protractor.Expe ...

Avoid connecting redux to a component in TypeScript and React

I am having an issue with the "connect" function not wrapping my App component, causing Redux to not work. I have tried cloning some repositories with react+redux+typescript and they all work fine, but my application does not. As a result, I am unable to ...

Having trouble with 'npm <script-command>' not working? Try changing it to 'npm run-script <script-command>' instead

Currently, I am configuring a node js backend to operate on TS for the first time within a mono-repo that has a specific folder structure. You can view the structure here. The package.json file is located in the main directory as shown below: "scr ...

encountered an issue when testing a dynamic route in Next.js with postman

I recently created a new API route named route.ts, where I included two different routes. One route retrieves all users from the database, while the other retrieves a specific user based on their ID passed as a query parameter. However, when testing these ...

Angular strictPropertyInitialization - best practices for initializing class members?

When initializing a component, I need to retrieve user information. However, with the Angular strict mode in place, I'm uncertain about where to fetch this data. I have considered 3 options. But which one is the most appropriate? Is there another alt ...

Utilizing generics within a function

Can you help me understand why I am getting an error message that says "Type 'AbstractPopup' is not assignable to type T" when using the return statement in the popupFactory(...) method? This code is just a test example for learning how generics ...

The type 'xxxx' is not compatible with the parameter type 'JSXElementConstructor<never>'

I am currently enrolled in a TypeScript course on Udemy. If you're interested, you can check it out here. import { connect } from 'react-redux'; import { Todo, fetchTodos } from '../actions'; import { StoreState } from '../red ...

Angular 13: SyntaxError Encountered: Token 'export' Not Recognized

After upgrading Angular from version 12 to 13, I encountered an error when running the app: "Uncaught SyntaxError: Unexpected token 'export'." Here are some additional details for context: In the angular.json configuration file, I had specified ...

Include the providers after declaring the AppModule

When it comes to Angular 2+, providers are typically registered in the following manner: // Using the @NgModule decorator and its metadata @NgModule({ declarations: [...], imports: [...], providers: [<PROVIDERS GO HERE>], bootstrap: [...] }) ...

Receiving an error when triggering an onclick event for a checkbox in TypeScript

I am creating checkboxes within a table using TypeScript with the following code: generateTable(): void { var table = document.getElementById("table1") as HTMLTableElement; if (table.childElementCount == 2) { for (var x = 0; x < 2; x++) ...

Angular 4: Unidirectional data flow from View to Component

Struggling to secure user credentials in my Angular form due to 2-way data binding displaying encrypted values within the component. Here's the code snippet: <form> <div class="input-group"> <span class="input-group-a ...

Struggling to make Mongoose with discriminator function properly

I seem to be facing an issue with my schema setup. I have defined a base/parent Schema and 3 children schemas, but I am encountering an error message that says: No overload match this call Below is the structure of my schema: import { model, Schema } fr ...

The ESLINT_NO_DEV_ERRORS flag appears to be ineffective in my Typescript project

Currently, my project involves using the following tools: Yarn Typescript Create React App ESLint Make (Makefile) Fish shell During development, I encounter ESLint errors that prevent my project from compiling. To run my project, I use make run, which es ...

Encountering an issue with compiling Angular due to a Type Inference error

interface Course { name: string; lessonCount: number; } interface Named { name: string; } let named: Named = { name: 'Placeholder Name' }; let course: Course = { name: 'Developing Apps with Angular', lessonCount: 15 }; named = ...

Can one inherit under specific conditions?

I have just started exploring the OOP paradigm and I am curious to know if it is possible to have conditional inheritance in TypeScript. This would help avoid repeating code. Here is what I have in mind. Any suggestions or recommendations are greatly appre ...

What steps should I take to fix the Typescript error showing up in my Next.js route?

import type { NextApiRequest, NextApiResponse } from "next"; import db from "../../app/libs/dbConn"; interface DataProps { auth: [ { name?: string; email?: string; passwordHash?: string; } ]; status: n ...

To allow users to sign in, the mutation can be filtered based on the boolean value of `isVerified

How can I filter and only allow users with isVerified === true to sign in? If it's false, the user should not be able to sign in through the mutation. Here is my code for the mutation: signin: async ( _: any, { credentials }: SignInArgs, ...

Challenges arise when integrating Angular with Firebase, particularly in the realms of authentication and user

Currently, I am working on a project using Angular and Firebase. However, in the auth.service.ts file, Visual Studio Code is not recognizing the imports for auth and User. import { auth } from 'firebase/app'; import { User } from 'fireba ...