Is it possible to define an interface to inherit keys from another interface?

I have two different interfaces that I need to align their key structure, but not necessarily the values they hold. One interface (Thing) is sourced from an external library, while the other interface (ThingOptions) is defined in my own project.

interface Thing {
  foo(value: number): void;
  bar(value: string): void;
  someOtherKey: null;
}

interface ThingOptions {
  foo: number;
  bar: string;
}

Is there a method to ensure that the keys in ThingOptions are included within the keys of Thing?

Answer №1

To implement compile-time checking for a scenario like this, you can create a type called KeysFrom<T, U>. This type ensures that the keys of one object are a subset of another.

type KeysFrom<T, U> = { [K in keyof U]: K extends keyof T ? U[K] : never }

By using

KeysFrom<{a: string}, {a: number}>
, you will see that it correctly resolves to {a: number}. However, with
KeysFrom<{a: string}, {b: number}
, it results in {b: never}. You can then assert that ThingOptions extends
KeysFrom<Thing, ThingOptions>
.

interface ThingOptions extends KeysFrom<Thing, ThingOptions> {
    foo: number;
    bar: string;
}

This approach works effectively by enforcing the constraint at compile time. If there is an incompatible property, such as in BadThingOptions, it will fail compilation.


Another method involves creating a separate type checker:

type KeysAreSubset<
    T,
    U extends { [K in keyof U]: K extends keyof T ? U[K] : never }
> = true;

With this technique, you introduce the check in its own line and ensure that any type U must conform to KeysFrom<T, U>. This way, any mismatch between keys will trigger an error during compilation.


Both these strategies provide compile-time validation, albeit requiring slight alterations to the original name and some additional code complexity. Nonetheless, they offer robust solutions based on your specific requirements. Best of luck implementing them!

Code Link

Answer №2

Can you use TypeScript with different interfaces?

No, it's not possible as the properties of the two interfaces are of different types.

While TypeScript may not provide a built-in safeguard for this issue, one workaround could be:

  let obj1 = {
    foo: v => "my string return value",
    bar: v => "2"
  } as Interface1;

  let obj2 = {
    foo: 1,
    bar: "2"
  } as Interface2;

  let propsOfObj1 = Object.keys(obj1);
  let propsOfObj2 = Object.keys(obj2);

  // To compare if all elements in the first array are contained in the second one, creating a function to compare two objects in this way might be the solution you're looking for.

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

Two services declared with "providedIn: 'root'" that have identical names

Imagine if there are two distinct services in two separate project categories, both sharing the same name. /app/services/category1/my.service.ts: @Injectable({ providedIn: 'root' }) export class MyService { foo() { return 'foo&apo ...

Is there a way to adjust this validation logic so that it permits the entry of both regular characters and certain special characters?

Currently, the input field only accepts characters. If any other type of character is entered, an error will be thrown as shown in the code below. How can I update this logic to allow not only letters but also special characters like hyphens and apostrop ...

Leveraging Angular 4-5's HttpClient for precise typing in HTTP requests

Utilizing a helper service to simplify httpClient calls, I am eager to enforce strong typing on the Observable being returned. In my service where I utilize the api Service and attempt to obtain a strongly typed observable that emits: export class ApiU ...

The data in DataTables is loading correctly, however, the buttons and sorting features are not operating as intended within Angular 4

I am currently working on an Angular 4 project where I need to display data in a table format using the DataTables library. While I have successfully implemented the hardcoded examples provided by DataTables with all the buttons functioning as expected, I ...

Using the VSCode debugger to place a breakpoint within a Typescript package that has been symlinked using `npm link`

I'm currently troubleshooting a NodeJS application and its associated typescript packages, which have been linked using `npm link`. The directory structure is as follows: /root/package-a # typescript package /root/package-b # another typescript packa ...

After upgrading to Angular 15, the Router getCurrentNavigation function consistently returns null

Since upgrading to angular 15, I've encountered a problem where the this.router.getCurrentNavigation() method is returning null when trying to access a state property passed to the router. This state property was initially set using router.navigate in ...

Invoke a custom AWS CodeBuild project in CodePipeline using a variety of parameters

Imagine having a CodePipeline with 2 stages structured like this: new codepipeline.Pipeline(this, name + "Pipeline", { pipelineName: this.projectName + "-" + name, crossAccountKeys: false, stages: [{ stageName: &apos ...

Using custom types for prop passing in Next.js with TypeScript

After making a http call, I obtain an array containing JSON data. This data is then assigned to a type called Service. type Service = { id?: string; name?: string; description?: string; }; The api call is made in getServerSideProps and the Service type is ...

MUI: Transforming the uncontrolled value state of Select into a controlled one with a new component

I'm attempting to develop an edit form for modifying data fetched from a database based on its ID. Here is what I have tried: import React, {FormEvent, useEffect, useState} from "react"; import TextField from "@material-ui/core/ ...

Typescript raises an error when providing a potentially null value (that is not null) to an unnamed callback function

When dealing with a property that starts as null, how can I pass it to an anonymous callback function expecting a non-null value without TypeScript throwing errors? I've tried wrapping the function call in an if statement to check for null at the cal ...

Leveraging getStaticProps in Next.js

I am currently embarking on my inaugural Nextjs project, focused on developing a basic blog utilizing the JSON placeholder API. Strangely, I am encountering an issue where the prop "posts" is being perceived as undefined. Can anyone provide assistance with ...

How can I uniquely combine a code with an existing CSS class and make modifications to it?

I am using ngx-skeleton-loader and I would like to change the color, but I am facing some difficulties. Here is an image that illustrates the issue. When looking at the developer tools, you can see the styles action in the styles action bar. .loader ...

Having difficulty properly streaming UI components with Vercel's AI-SDK

Recently, I've been diving into the new Vercel's AI-SDK to expand my skills. My current project involves developing a persona generator that takes specific guidelines as inputs and generates persona attributes according to a given Zod schema. B ...

How can we access child components in vanilla JavaScript without using ng2's @ViewChild or @ContentChild decorators?

Recently, I delved into the world of using ViewChildren and ContentChildren in Angular 2. It got me thinking - can these be implemented in ES6 without TypeScript annotations? The TypeScript syntax, according to the official documentation, looks something ...

It is impossible for me to invoke a method within a function

I am new to working with typescript and I have encountered an issue while trying to call the drawMarker() method from locateMe(). The problem seems to be arising because I am calling drawMarker from inside the .on('locationfound', function(e: any ...

How can the outcome of the useQuery be integrated with the defaultValues in the useForm function?

Hey there amazing developers! I need some help with a query. When using useQuery, the imported values can be undefined which makes it tricky to apply them as defaultValues. Does anyone have a good solution for this? Maybe something like this would work. ...

The name 'Landbot' cannot be located. Have you meant to type '_landbot' instead?

I'm currently in the process of integrating Landbot into my React.js application with TypeScript. I'm following this [doc] 1. However, I'm facing an issue where the code inside useEffect (new Landbot.Container) is causing an error. 'C ...

The element is assumed to have an 'any' type due to the index expression not being of type 'number'. - Error in Index Signature

I've recently started using TypeScript and encountered the following issue: Element implicitly has an 'any' type because index expression is not of type 'number' This error message appears on this line --> const { status, msg ...

What steps are involved in setting up a sorting feature?

In order to utilize the array.sort() function, a number-returning function must be specified. Typically, it would look something like this: myArray.sort((item1, item2) => a < b); However, I am aiming for a different structure: myArray.sort(by(obj ...

Issue with ngRX infinite loop caused by the updateOne function in the adapter

Hey there, I'm struggling to figure out why my code is stuck in an infinite loop. I've searched online extensively but haven't found a solution that fits my specific issue. This is the code snippet causing the problem: /** * CODE ...