Is it possible to verify type property names using a union type?

Given

type UnionType = 'prop1' | 'prop2' | 'prop3';

type DerivedType = {
  prop1: string;
  prop2: number;
  prop3: boolean;
};

Is there a method to define DerivedType in such a way that if I introduce a new member to UnionType without including the corresponding property in DerivedType, TypeScript will raise an error?

If all the properties had identical types, this would be straightforward; however, they do not.

I am not looking for Record<UnionType, any> - I want distinct types for each property.

The specific scenario involves a union type that is based on keyof another type; the "derived" type outlines configurations for each of the properties. The objective is to maintain consistency among all these types.

Answer №1

If you're unable or unwilling to modify the structure so that UnionType is based on DerivedType, or if both UnionType and DerivedType cannot be defined in terms of something else, a custom utility type CheckKeys<K, T> can be created. This utility type will result in T, but will trigger a compiler error unless all keys in T precisely match

K</code without any omissions or extras (though there may be some exceptional cases).</p>
<p>One approach to achieve this is as follows:</p>
<pre><code>type CheckKeys<
  K extends PropertyKey,
  T extends Record<K, any> & Record<Exclude<keyof T, K>, never>
> = T;

In this setup, T is constrained to ensure it contains all keys from K (as it extends Record<K, any> utilizing the Record utility type). Additionally, through intersection, any keys in T not present in K are mandated to have properties of the impossible never type. Since only never is assignable to

never</code, and setting property types to <code>never</code explicitly is unlikely, this effectively enforces the desired restriction. Let's put it to the test:</p>
<pre><code>type UnionType = 'prop1' | 'prop2' | 'prop3';

type DerivedType = CheckKeys<UnionType,
  { prop1: string; prop2: number; prop3: boolean; }
>; // success

type ExtraKey = CheckKeys<UnionType,
  { prop1: string, prop2: number, prop3: boolean, prop4: Date } // error!
// Types of property 'prop4' are incompatible.
>

type MissingKey = CheckKeys<UnionType,
  { prop1: string, prop2: number } // error!
// Property 'prop3' is missing.
>

Results look promising. DerivedType remains unchanged and compiles error-free. However, introducing or removing keys triggers the necessary compiler alerts pinpointing the issue.

Playground link for 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

Encountering an error with Angular2 when referencing node modules

I encountered an issue when trying to use angular2 from the node_modules directory. Can anyone guide me on how to resolve this error? Is there something specific I need to include in my HTML file? I am looking for a Git repository where I can access Angu ...

What is the process for removing a document with the 'where' function in Angular Fire?

var doc = this.afs.collection('/documents', ref => ref.where('docID', '==', docID)); After successfully retrieving the document requested by the user with the code above, I am unsure of how to proceed with deleting that do ...

Exploring arrays within objects with Angular

REACT: this.countries = this.api.fetchAllCountries(); this.countries.forEach(item => { this.countryData.push(item); }); VUE: <div v-for="country in countryData" @click="displayCountryInfo(country ...

Error encountered during conversion from JavaScript to TypeScript

I am currently in the process of converting JavaScript to TypeScript and I've encountered the following error: Type '(props: PropsWithChildren) => (any[] | ((e: any) => void))[]' is not assignable to type 'FC'. Type '(a ...

Using async/await does not execute in the same manner as forEach loop

Here is a code snippet that I have been working with. It is set up to run 'one' and then 'two' in that specific order. The original code listed below is functioning correctly: (async () => { await runit('one').then(res ...

How can I make sure that my function returns a mutated object that is an instance of the same class in

export const FilterUndefined = <T extends object>(obj: T): T => { return Object.entries(obj).reduce((acc, [key, value]) => { return value ? { ...acc, [key]: value } : acc; }, {}) as T; }; During a database migration process, I encounte ...

Implementing Adsterra in your next.js or react.js project: A step-by-step guide

Currently, I am working on integrating the Adsterra Banner 300x50 into a ts/js reactjs + nextjs project. The provided script code from Adsterra is as follows: <script type="text/javascript"> atOptions = { 'key' : 'XXXXXX&a ...

Create a custom class that functions similarly to a dictionary

Is it not feasible to achieve this? interface IMap { [key: string]: string; } class Map implements IMap { public foo = "baz"; } But instead of success, I encounter the error: TS2420:Class 'Map' does not correctly implement 'IMap& ...

I am verifying the user's login status and directing them to the login page if they are not already logged in

My goal is to utilize ionViewWillEnter in order to verify if the user is logged in. If the check returns false, I want to direct them to the login page and then proceed with the initializeapp function. My experience with Angular and Ionic is still limite ...

Organize nested tuples and maintain their sequence

I am attempting to achieve a functionality similar to the following: type Type = object; type TypeTuple = readonly Type[]; function flattenTuples<T extends readonly (Type | TypeTuple)[], R = Flatten<T>>(...tuples: T): R { // code to flatten ...

What is the syntax for creating a link tag with interpolation in Angular 2 / Ionic 2?

As I work on developing an app using Ionic 2/Angular 2, I have encountered a challenge that I am struggling to overcome. Let me provide some context: I am retrieving multiple strings from a webservice, and some of these strings contain links. Here is an e ...

Adding a declaration file to a package that relies on an external declaration file can be achieved by following these

In the process of developing a library that relies on another package lacking a declaration file in its npm package, I have successfully installed the necessary declaration file with typings. Everything seems to be working well. Yet, the question remains: ...

How to utilize a defined Bootstrap Modal variable within a Vue 3 single file component

I'm diving into the world of TypeScript and Vue 3 JS. I created a single-file-component and now I'm trying to implement a Bootstrap 5 modal. However, my VSCode is showing an error related to the declared variable type. The error message reads: ...

Tips for directing your attention to an input field in Angular

I'm struggling to find a simple solution for setting focus programmatically in Angular. The closest answer I found on Stack Overflow is about dynamically created FormControl, but it seems more complex than what I need. My situation is straightforward ...

How can I limit generic types to only be a specific subtype of another generic type?

Looking to create a data type that represents changes in an object. For instance: const test: SomeType = { a: 1, b: "foo" }; const changing1: Changing<SomeType> = { obj: test, was: { a: test.a }, now: { a: 3 ...

Utilizing the <HTMLSelectElement> in a Typescript project

What exactly does the <HTMLSelectElement> do in relation to a TypeScript task? let element = <HTMLSelectElement> document.querySelector('#id_name'); The HTMLSelectElement interface, similar to the one mentioned in TypeScript, is exp ...

Tips for successfully sending an API request using tRPC and NextJS without encountering an error related to invalid hook calls

I am encountering an issue while attempting to send user input data to my tRPC API. Every time I try to send my query, I receive an error stating that React Hooks can only be used inside a function component. It seems that I cannot call tRPC's useQuer ...

Encountering an obscure package error while attempting to install an NPM package

After running the following command on my node application: npm install --save-dev typescript I encountered this error message: > <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="563a3f3426271667786e786e">[email pro ...

Enabling or disabling a button dynamically in Ionic based on a conditional statement

I am looking to dynamically enable or disable buttons based on specific conditions. The data is retrieved from Firebase, and depending on the data, I will either enable or disable the button. For example, if a user passes the First Quiz, I want to enable ...

Navigate to the logout page automatically when closing the final tab

In order to comply with the requirement, I need to log out the user when they close the last tab on the browser. ngOnInit() { let counter: any = this.cookieService.get('screenCounterCookie'); counter ? ++counter : (counter = & ...