Tips for defining an array containing only one alias that has been declared in a type alias

Suppose I have declared a type alias in TypeScript like this:

export type PlatformType = 'em' | 'ea' | 'hi';

How can I specify a property in an interface that only accepts an array containing one instance of each PlatformType? For instance, I would like to achieve the following:

export interface Constants {
  platformTypes: PlatformType[]; // what is the correct way to define the type for platformTypes?
}

When creating an object of type Constants, it should adhere to this structure:

export const constants: Constants = {
  platformTypes: ['em', 'ea', 'hi']
}

Essentially, I want to trigger an error in scenarios such as:

export const constants: Constants = {
  platformTypes: ['em', 'ea'] // should result in an error as 'hi' is missing
}

or

export const constants: Constants = {
  // This will throw an error since 'extra' is not part of the PlatformType alias
  platformTypes: ['em', 'ea', 'hi', 'extra']
}

or

export const constants: Constants = {
  platformTypes: ['em', 'em', 'ea', 'hi'] // should trigger an error due to duplicate 'em'
}

Answer №1

It would be advisable to establish a permutation encompassing all permissible tuples.

For example, if there is a union of three elements, it is necessary to generate a minimum of 6 tuples:

["em", "ea", "hi"] | ["em", "hi", "ea"] | ["ea", "em", "hi"] | ["ea", "hi", "em"] | ["hi", "em", "ea"] | ["hi", "ea", "em"]

This is due to the fact that a union represents an unordered data structure.

export type PlatformType = 'em' | 'ea' | 'hi';


// credits goes to https://twitter.com/WrocTypeScript/status/1306296710407352321
type TupleUnion<U extends string, R extends any[] = []> = {
    [S in U]: Exclude<U, S> extends never ? [...R, S] : TupleUnion<Exclude<U, S>, [...R, S]>;;
}[U];

export interface Constants {
  platformTypes: TupleUnion<PlatformType>; // how to declare a type for platformTypes?
}

export const constants: Constants = {
  platformTypes: ['em', 'ea', 'hi'] // ok
}

export const constants2: Constants = {
  platformTypes: ['em', 'ea'] // error
}

export const constants3: Constants = {
  platformTypes: ['em', 'ea', 'hi', 'extra'] // error
}

export const constants4: Constants = {
  platformTypes: ['em', 'em', 'ea', 'hi'] // error
}

Playground

Remember, the order of unions in typescript can be complex. Please refer to this question and this issue for more information.

You can explore additional examples on my blog.

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

Attempting to grasp the concept of Typescript generics

I have a function defined as follows: interface ExtraModels extends Model { unknown: string } const write = async (data: ExtraModels[]) => { console.log(data[0].unknown) } This function is currently working. However, I want to modify it to: cons ...

The file could not be located on the server during the project build and upload process

Presently, I'm engrossed in a project involving Angular 9 and ASP Core 3. You can find the website at: Nevertheless, encountering an error when trying to access this URL: http://mag-testcpl.astromap.ir/assets/vendors/global/toastr.css The culprit ...

Service for language translation in Angular

I attempted to use an angular translation service to translate English words to Chinese using a key-value mapping approach, but unfortunately, I was unsuccessful. Does anyone have any suggestions? Here is the JSON mapping: "At most {{ number }} wrods ...

What is the best way to convert JSON into a complex object in Typescript and Angular?

In my Typescript class for an Angular version 5 project, I have a JavaScript function that generates a style object. Here is the function: private createCircle(parameters: any): any { return new Circle({ radius: parameters.radius, ...

Declaratively assign ambient typings to an unfamiliar object in Typescript

I am facing an issue with an external library named "gapi" that is set to a property on the window object as window.gapi. I would like to keep it there while using the @types/gapi declaration. Is there a way to achieve this, like the following code snippet ...

Importing a file using its absolute path in JavaScript

Within the dependencies directory, there exists a module named foo: import foo from '../dependencies/foo'; // This import statement works as intended The challenge arises when attempting to import from a different path due to deployment in an AW ...

Tips for incorporating Extract<T, U> with a nested variant?

I've encountered an issue with generated types. A particular API is providing me with two types, and I want to create distinct aliases for each. In TypeScript, we can utilize Extract<> to assist with this: type Add = { type: 'add' ...

The function threw an error: "TypeError: this.registeredUserArray.some is not a function"

I have been attempting to store a registered user object inside localstorage. However, when I try to retrieve or set those values from localstorage in an array and parse it back to an object, I encounter an error stating that ".push" or ".some" is not a ...

Guide to starting a typed array in Typescript

I have an array called "cart" of objects that is initially empty, but structured like this: cart:[{name:any, rate:number, qty:number, discount:number, subtotal:number}] When I attempt to add data to it like so: cart:[{name:any, rate:number, qty:number, ...

Improving a lengthy TypeScript function through refactoring

Currently, I have this function that I am refactoring with the goal of making it more concise. For instance, by using a generic function. setSelectedSearchOptions(optionLabel: string) { //this.filterSection.reset(); this.selectedOption = optionLa ...

Is it possible to create a function that only accepts a union type if it includes a specific subtype within it?

Is there a way to define the function processArray so that it can handle arrays of type string[], without explicitly mentioning individual types like type1 or type2? For instance, could we indicate this by using arr: type1 | type2? The objective here is t ...

The correct way to incorporate a global property into a component template (using Vue 3, Vite, TypeScript, and the Composition API)

The component's property is not functioning properly https://i.sstatic.net/qaUG9.png src/main.ts import { createApp } from 'vue' import languagePlugin from '@/plugins/languagePlugin' import App from './App.vue' const a ...

The issue encountered in Cocos Creator 3.8 is the error message "FBInstant games SDK throws an error stating 'FBInstant' name cannot be found.ts(2304)"

Encountering the error "Cannot find name 'FBInstant'.ts(2304)" while using FBInstant games SDK in Cocos Creator 3.8. Attempting to resolve by following a guide: The guide states: "Cocos Creator simplifies the process for users: ...

What is the process for incorporating a custom type into Next.js's NextApiRequest object?

I have implemented a middleware to verify JWT tokens for API requests in Next.js. The middleware is written in TypeScript, but I encountered a type error. Below is my code snippet: import { verifyJwtToken } from "../utils/verifyJwtToken.js"; imp ...

What is the reason for requiring an ES7/array polyfill even if the tsconfig target is established as ES5?

My tsconfig.json file contains the following settings, including adding "es2017" for using Array.includes: { "compilerOptions": { "lib": [ "es6", "es2017", "dom" ], "module": "es6", "target": "es5" } } However, I rea ...

TypedScript: A comprehensive guide to safely omitting deep object paths

Hi there, I have a complex question that I would like some help with. I've created a recursive Omit type in TypeScript. It takes a type T and a tuple of strings (referred to as a 'path'), then removes the last item on the path and returns t ...

Encountering a Problem on Heroku: TypeScript Compilation Error with GraphQL Files - TS2307 Error: Module 'graphql' Not Found or Its Type Declarations Missing

While trying to compile my typescript project with graphql files for deployment on Heroku, I encountered the following error message: node_modules/@types/graphql-upload/index.d.ts(10,35): error TS2307: Cannot find module 'graphql' or its correspo ...

Achieving (keyup.enter) event on an option within a datalist in Angular 6

How can I trigger the (keyup.enter) event on an option within a datalist in Angular 6? This is my HTML Code: <input list="filteredArray" (keyup)="filterEmployee(empForm.controls['empname'].value)" type="text" formControlName="empname" /> ...

Using an object as an array index in Javascript

I have been utilizing a crossword application from this specific repository: https://github.com/jweisbeck/Crossword . The issue I am facing is that the program is using jquery version 1.6.2 while my entire project is built on jquery-3.1.1 version. The erro ...

Discovering the Object with the Lowest Key Value in Typescript

Within my TypeScript code, I have defined a List as myList: Package[]. The structure of the Package model is outlined below - export class Package { ID: Number; Price: Number; } I am trying to retrieve a Package object with the lowest Price value using ...