Is there a way to restrict an array to only accept distinct string literals?

export interface IGUser {
  biography: string;
  id: string;
  ig_id: string;
  followers_count: number;
  follows_count: number;
  media_count: number;
  name: string;
  profile_picture_url: string;
  shopping_product_tag_eligibility: boolean;
  username: string;
  website: string;
}

const values: keyof IGUser = ['biography', ''];

https://i.sstatic.net/WfH8Z.png

Is there a way to restrict the array to only allow one instance of biography?

Answer №1

If you're looking to remove duplicates in an array, one approach is to utilize a function designed specifically for that purpose. Check out this helpful resource on how to delete duplicate elements from an array: Removing Duplicate Elements From Arrays

Answer №2

Yes, it is feasible but only up to a certain number of keys. Eventually, the computation of that singular array literal type will become too costly due to its reliance on the length of your Union Type (keyof IGUser). This will trigger a "Type instantiation is excessively deep and possibly infinite" error.

Nevertheless, taking inspiration from this response by Mu Tsun Tsai on the topic of Unordered tuple type, I devised the following solution. By utilizing a Mapped Type and Exclude, you can ensure uniqueness of all literals in your array. Essentially, this method calculates all possible valid combinations based on the union of your initial object keys. It's worth noting that this approach prohibits any duplicate literals, not just "biography"

interface IGUser {
  biography: string;
  name: string;
  username: string;
//   id: string;
//   ig_id: string;
//   followers_count: number;
//   follows_count: number;
//   media_count: number;
//   profile_picture_url: string;
//   shopping_product_tag_eligibility: boolean;
//   website: string;
}

type SingleBiographyKeyArray<T extends string, R extends any[] = []> = R | {
    [K in T]: SingleBiographyKeyArray<Exclude<T, K>, [K, ...R]>
}[T];

let values: SingleBiographyKeyArray<keyof IGUser> = []; // valid
values = ["biography"] // valid
values = ["biography", "name", "username"] // valid

values = ["biography", "biography", "name"];
// ~~~ invalid
values = ["biography", "username", "name", "name"];
// ~~~ invalid

TypeScript Playground

Answer №3

If you have a specific set of allowed values, you can achieve this by following the instructions at https://tsplay.dev/NlXgrN

type ValidateUniqueArray<T, A extends T[]> =
  | A extends [infer F, ...infer L]
  ? (L extends Exclude<T, F>[]
    ? [F, ...ValidateUniqueArray<Exclude<T, F>, L>]
    : [F, Exclude<T, F>?]
  ) : [T?, ...unknown[]]
  ;

type ValidateCompleteUniqueArray<T, A extends any[]> =
  | [T] extends [never]
  ? []
  : A extends [infer F, ...infer L]
  ? (F extends T
    ? [F, ...ValidateCompleteUniqueArray<Exclude<T, F>, L>]
    : [T, ...ValidateCompleteUniqueArray<T, L>]
  ) : [T]
  ;

type conforms<T, V> = T extends V ? T : V;

function uniqueArray<T>() {
  return {
    partial<A extends T[]>(a: conforms<A, ValidateUniqueArray<T, A>>): A {
      return a as A;
    },
    complete<A extends T[]>(a: conforms<A, ValidateCompleteUniqueArray<T, A>>): A {
      return a as A;
    },
  }
}

let a1 = uniqueArray<1 | 2 | 3 | 4>().partial([
  1, 2, 3, 4 // all good
])
let a2 = uniqueArray<1 | 2 | 3 | 4>().partial([
  1, 1 // Type '1' is not assignable to type '2 | 3 | 4'.(2322)
])
let a3 = uniqueArray<1 | 2 | 3 | 4>().partial([
  1, 'foo' // Type 'string' is not assignable to type '2 | 1 | 3 | 4'.(2322)
])

let b1 = uniqueArray<1 | 2 | 3 | 4>().complete([
  1, 2, 3, 4 // all good
])
let b2 = uniqueArray<1 | 2 | 3 | 4>().complete([
  1, 2, 3, 1 // Type '1' is not assignable to type '4'.(2322)
])
let b3 = uniqueArray<1 | 2 | 3 | 4>().complete([
  1, 2, 3, 'foo' // error
])
let b4 = uniqueArray<1 | 2 | 3 | 4>().complete([
  1, 2, 3 // Argument of type '[1, 2, 3]' is not assignable to parameter of type '[1, 2, 3, 4]'.
])

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 Typescript compiler will continue to generate JavaScript code even if there are compilation errors

As a fresh learner of TypeScript, I have been experimenting with some basic concepts. Below is the code from my file app1.ts: class Monster { constructor(name, initialPosition) { this.name = name; this.initialPosition = initialPosition ...

Angular Ahead-of-Time (AOT) compilation causes multiple route definitions to be

Having a bit of trouble configuring ahead-of-time compilation for my lazy-loaded Angular app. The lazy-loaded routes are specified in the app.routes.ts file, which is imported by app.module.ts. Running ngc results in the content of app.routes.ts being mer ...

Encountering complications when importing TypeScript declarations

I am facing a problem with importing declarations from an extended file (I am utilizing this typing). As per the example, I have included this code in my project: import * as SockJS from 'sockjs-client'; import BaseEvent = __SockJSClient.BaseEve ...

The creation of a Firebase user account with the specified email and password

I'm currently facing an issue while creating a new user with email and password using firebase authentication. The problem arises when I try to access the displayName from the returned async call before the updateProfile function, as it returns a null ...

Assigning to a constrained type with an indexable signature results in failure

When using typescript 4.7.2, I encountered an issue where the following code fails only when assigning a value: type IndexableByString = { [k: string]: any }; function test<T extends IndexableByString>(target: T, key: string) { var prop = target ...

Failure of VSCode breakpoints to function properly with TypeScript npm linked package

I am developing a Next.js app using TypeScript and my .tsconfig file includes the following configurations: { "compilerOptions": { "baseUrl": "src", "experimentalDecorators": true, "target": & ...

Mozilla struggles to interpret JSON data

When using Angular2 (RC4), I utilize this code snippet to retrieve data from my WebApi: getAppointment(id: number): Observable<Event> { return this._http.get(this._serviceUrl + 'get/' + id) .map(this.extractData) .catch ...

Important notice: It is not possible to assign refs to function components. Any attempt to do so will result in failure. If you intended to assign a ref, consider

My console is showing a warning when I use the nextJs Link component. Can someone assist me in resolving this issue and providing an explanation? Here is the message from the console: https://i.stack.imgur.com/jY4FA.png Below is a snippet of my code: im ...

Troubleshooting issue with getServerSideProps not functioning in Next.js while utilizing Next-redux-wrapper and TypeScript

When attempting to trigger an action as outlined in the documentation using the getServerSideProps function with the help of next-redux-wrapper store and redux-thunk, I am encountering the following TypeScript error: ts(2322): Type '({ req }: GetServe ...

Is it possible to showcase a unique date for every item that gets added to a list?

I am new to using React, so please bear with me. I want to be able to show the date and time of each item that I add to my list (showing when it was added). I am struggling to get this functionality working with my current code. Any help or explanation o ...

When incorporating an array as a type in Typescript, leverage the keyof keyword for improved

I am facing a situation where I have multiple interfaces. These are: interface ColDef<Entity, Field extends keyof Entity> { field: Field; valueGetter(value: Entity[Field], entity: Entity): any } interface Options<Entity> { colDefs ...

Unable to make custom font work in TailwindCSS and ReactJS project

I have incorporated a custom font into my projects using React, TypeScript, TailWind, and NextJS. The font file is stored in the /fonts directory with the name Glimer-Regular.ttf. To implement the font, I added the following code snippet to my global.css ...

Angular 2 lacks compatibility with SVG

I have a website where I want to include SVG images inline with my HTML using Angular 2. However, when I try to load the SVG icons within a component, they do not display correctly. Instead, I see the following: https://i.sstatic.net/Ozo6E.png You can vi ...

The vertical scrolling functionality of the MUI DataGrid in Safari may occasionally fail to work

Utilizing the <Box> component from MUI core and the <DataGrid> component from MUIX, along with some other components, I have created a data grid that has the following appearance: https://i.sstatic.net/Gc8sP.png When the number of rows exceed ...

The attribute 'date' is not found within the class 'EmployeeScheduleExceptionModel', however, it is present in the parent class from which it inherits

I am working on a TypeScript project and I have defined my configurations in the tsconfig.json file as shown below: { "include": ["src*"], "compilerOptions": { "target": "es2021", &q ...

The callback function inside the .then block of a Promise.all never gets

I'm currently attempting to utilize Promise.all and map in place of the forEach loop to make the task asynchronous. All promises within the Promise.all array are executed and resolved. Here is the code snippet: loadDistances() { //return new Prom ...

Exploring the power of Angular 10 components

Angular version 10 has left me feeling bewildered. Let's explore a few scenarios: Scenario 1: If I create AComponent.ts/html/css without an A.module.ts, should I declare and export it in app.module.ts? Can another module 'B' use the 'A ...

When debugging in Visual Studio 2013, Typescript variables/fields consistently show up as undefined

What is the reason behind the properties/field variables in Typescript being consistently undefined during debugging in Visual Studio 2013? ...

Tips for parsing a string object in JSON without a preceding double quote

I'm working with an array in my Angular application, for example: searchTerm : any[] In the context of a textbox value like {'state':'tn'}, I'd like to push this to the searchTerm array. Currently, I achieve this by adding t ...

Why is webpack attempting to package up my testing files?

In my project, I have two main directories: "src" and "specs". The webpack configuration entrypoint is set to a file within the src directory. Additionally, the context of the webpack config is also set to the src directory. There is a postinstall hook in ...