Guaranteeing the Originality of Literal Values within a Record Category

Consider the code snippet below:

const VALUES = {
    field1: "fieldA",
    field2: "fieldB",
} as const


export type RecToDU<T> = {
    [K in keyof T]: T[K]
}[keyof T]

type VALUESLiterals = RecToDU<typeof VALUES>

This results in:

type VALUESLiterals = "fieldA" | "fieldB"

Now, the goal is to verify that all literal values in the type are unique. For example:

const VALUE = {
    field1: "fieldA",
    field2: "fieldB",
    field3: "fieldA" // "fieldA" is repeated
} as const

type VALUESLiterals = RecToDU<typeof VALUES>

In this case, we want the output to be never instead of:

type VALUESLiterals = "fieldA" | "fieldB"

This is because field3 also contains the literal value fieldA, which already exists in field1. Therefore, if there are duplicate literal values, the entire type should evaluate to never.

Answer №1

When T does not have any duplicate property values, the desired outcome for RecToDU<T> is to encompass all its property value types as a union; otherwise, it should be set to never. The procedure to compute the union of property value types in T involves indexing into T with the union of its keys: T[keyof T] (view Q/A here) .

The definition for RecToDU<T> can take shape as a conditional type structured like this:

type RecToDU<T> = XXX extends YYY ? T[keyof T] : never
or perhaps
type RecToDU<T> = XXX extends YYY ? never : T[keyof T]
. Now, let's figure out what XXX and YYY will be.

One method to approach this is:

type RecToDU<T> = unknown extends {
   [K in keyof T]-?: T[K] extends Omit<T, K>[Exclude<keyof T, K>] ? unknown : never
}[keyof T] ? never : T[keyof T]

Explaining further:

{ [K in keyof T]-?: T[K] extends Omit<T, K>[Exclude<keyof T, K>] ? unknown : never }

This process involves mapping over each property key K in T, and comparing each property value T[K] to

Omit<T, K>[Exclude<keyof T, K>]
. In simpler terms,
Omit<T, K>[Exclude<keyof T, K>]
establishes the union of all property value types in T except at the specified key K.

For instance, if T is {a: 0, b: 1, c: 2} and K is "a", then T[K] becomes 0. Omit<T, K> would be {b: 1, c: 2}, and Exclude<keyof T, K> translates to "b" | "c", thus resulting in

Omit<T, K>[Exclude<keyof T, K>]
equating to 1 | 2. Hence, when we compare 0 extends 1 | 2 ? ..., we assess whether the property at that particular key K appears elsewhere in the object or not.

If

T[K] extends Omit<T, K>[Exclude<keyof T, K>]
evaluates to true, it implies duplication of property values across different properties. On the other hand, false indicates uniqueness for the respective property. Depending on this evaluation, either the unknown type (for duplicates) or the never type (for unique values) is returned, shaping the resultant object accordingly.

With rigorous testing and consideration of specific use cases, adjustments may be required in defining RecToDu<T> based on varying object structures and scenarios involving optional properties, index signatures, and data types not limited to literals alone.

Test code in TypeScript 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

The implementation of reducers in Redux Toolkit and TypeScript allows for efficient state management and

When I tried to integrate Typescript into my Redux toolkit for the first time, I encountered an issue while defining my reducers in Redux Slice. import { createSlice } from "@reduxjs/toolkit"; import { data } from "../data/Reviews"; ...

How can I effectively filter the data returned by consuming an API in JSON through an Angular service?

My Angular 6 project includes a UsersService that is injected into the UsersComponent. Originally, the component displayed mock data in the form of a string array. However, it now consumes JSON data from an API provided by JSONPlaceholder via the UsersSer ...

Build modern web applications with Visual Studio 2015/2017 using React and TypeScript for dynamic

Has anyone successfully found a comprehensive react+typescript tutorial for a Visual Studio 2015/2017 MVC project that actually works, from beginning to end? I attempted to install the NuGet packages "Reactjs Mvc4" and "typescript", created a .tsx file, a ...

Show information from a chart depending on the data retrieved from an API request

I am currently learning how to use React and incorporating a store into my application. My goal is to have 2 components, one main component and a child component. The main component will make an API call to retrieve data, which will then be passed to the c ...

CPU usage spikes after launching a Cordova project in Visual Studio 2015 RTM

If you're looking for the source code of the project, you can find it at https://github.com/Yaojian/Ionic-TypeScript-Starter/. I decided to create a Visual Studio project by forking https://github.com/Justin-Credible/Ionic-TypeScript-Starter/ and fol ...

Throw an error of Type - TypeError when the provided prop is beyond the permissible range

I am working on a component that accepts two props - children (React elements) and index. The purpose of this component is to return the child element at a specific index when the index is passed in. However, I want to enhance my types to throw a type er ...

having trouble retrieving information from mongodb

Currently working with nestjs and trying to retrieve data from a collection based on the 'name' value. However, the output I am getting looks like this: https://i.stack.imgur.com/q5Vow.png Here is the service code: async findByName(name):Promi ...

Is the stepper's vertical line separating when the label extends onto multiple lines?

I'm facing an issue with the text inside my MaterialUI Stepper // StepLabel, where it sometimes wraps over multiple lines. Is there a way to keep the vertical StepConnectors attached to the StepIcons regardless of the number of lines of text in the l ...

Stop unwanted clicking on inactive buttons in Angular

I want to make sure that disabled buttons cannot be clicked by users who might try to remove the disabled attribute and trigger an action. Currently, I have this code to handle the situation: <button [disabled]="someCondition" (click)="executeAction()" ...

Conceal data stored in session storage using Angular

My single page application in Angular 5 utilizes session storage to store various navigation parameters, flags, and information. However, these session storage values are visible and can be modified by end users through the browser's Application -> ...

arrange the elements in an array list alphabetically by name using the lodash library

Is there a way to alphabetically sort the names in an array list using JavaScript? I attempted to achieve this with the following code: const sample = [ { name: "AddMain", mesg: "test000" }, { name: "Ballside", ...

On the application's user interface, the contact list from a mobile device

I have successfully integrated the Contacts native plugin from Ionic 3 into my app. While it is functioning properly, I am facing an issue with implementing it within the app's UI. Currently, the contact list loads outside the app and only returns to ...

Place the cursor at the conclusion of the text box

I am working on creating a user input form for chat messaging and I need some help. Here is the HTML-code snippet that I am currently using: HTML-code Currently, when the user presses ENTER, I retrieve the text from the textbox and save it. If the user ...

Assigning union values to an object array: a guide for Typescript

When working with union typed values in an object array, how should the setState() function be implemented? enum SomeStateEnum { IsRunning, Name, } type PersonState = { [SomeStateEnum.IsRunning]: boolean; [SomeStateEnum.Name]: string; }; const st ...

Learn how to send an SMS using Angular and Ionic 4 without having to open the native SMS app

I have been actively monitoring the GitHub repository for the Ionic Native SMS plugin at https://github.com/cordova-sms/cordova-sms-plugin. Following the suggested configuration from the repo, I have set it up as follows: var options = { repla ...

Angular 5 ngx-modialog issue TS2307: Module 'ngx-modialog/plugins/vex' not located

After installing module ngx-modialog using the Angular 5 CLI like this: npm install --save ngx-modialog I then added it to my app.module.ts: import { VexModalModule } from "ngx-modialog/plugins/vex"; import { ModalModule } from "ngx-modialog"; @NgModul ...

What is the significance of incorporating react context, createContext, useContext, and useStore in Mobx?

In my Typescript application, I rely on Mobx for persistence and have created a singleton class called MyStore to manage the store: export class MyStore { @observable something; @observable somethingElse; } export myStore:MyStore = new MyStore(); ...

When using `JSON.stringify`, the resulting data may vary from the original object

Here is the code snippet in question: console.log("444444: ", profile, JSON.stringify(profile)) Upon checking the log output: https://i.stack.imgur.com/LzalV.png I am trying to understand why I cannot see the value: [0] present Additionally, ...

When working with Angular 2 and Typescript, a common error message that may be encountered is "TypeError

Currently diving into Angular 2 and encountered a stumbling block while attempting to create a service. Despite my efforts in finding a solution, I seem to be missing something crucial. Error: A problem arises in angular2-polyfills.js:1243 with the error ...

Implement FieldResolver in TypeGraphQL for an array of objects

My current dilemma revolves around a specific issue related to the definition of my Cart type, which is structured as follows: @ObjectType() export class Cart { @Field(() => ID) id: string; @Field((_type) => String) ownerId: String ...