Limit the range of potential inputs for the function parameter

class Coordinate {
  constructor(readonly x: number, readonly y: number) {}
}

const Up = new Coordinate(0, -1);
const Right = new Coordinate(1, 0);
const Down = new Coordinate(0, 1);
const Left = new Coordinate(-1, 0);

// How can we restrict the direction parameter to only accept values of Up, Right, Down, or Left?
function move(direction: Coordinate) {
    ...
}

Is there a way to ensure that the direction parameter is limited to either Up, Right, Down, or Left?

Answer №1

If you want to constrain a TypeScript function input to specific values, you must define those values at the type level using "literal" types. These types only accept particular values, allowing you to create restrictions by combining these literal types as unions.

Within TypeScript, primitive literal types exist for strings like "hello", numbers like 123, boolean values like true, and special types such as null and undefined. Additionally, there are unique symbols and enums for numeric and string literals.

Unfortunately, TypeScript lacks literal object types, preventing the definition of specific objects as distinct types. Using generics can provide a solution by making properties generic, enabling distinctions between approved values at the type level.


An alternative method is to utilize literal types like string enums to designate approved objects through key-value mappings. By leveraging an enum akin to Direction, you can map each direction to its associated coordinates and ensure that the move() function accepts only these predefined values.

Ultimately, depending on your requirements, you can adopt either approach to restrict function inputs based on specific values in TypeScript.

Answer №2

One approach you could take is outlined below, although it comes with some limitations:

class Coordinate<X extends number, Y extends number> {
  constructor(
    readonly x: X,
    readonly y: Y
  ) {}
}

const Up = new Coordinate(0, -1);
const Right = new Coordinate(1, 0);
const Down = new Coordinate(0, 1);
const Left = new Coordinate(-1, 0);

type Direction =
  typeof Up |
  typeof Right |
  typeof Down |
  typeof Left;

function move(direction: Direction) {
  // ...
}

move(Up);
move(new Coordinate(1, 0));
move(new Coordinate(1, 1)); // Error
  • Direct equality comparison between direction and the constants won't work as it compares instances, not values.
  • You'll need to deal with a type that includes generics.

Playground

To address these limitations, consider this alternative approach:

class Coordinate {
  readonly #key = {}
  private constructor(
    readonly x: number,
    readonly y: number
  ) {}

  static Up = new Coordinate(0, -1);
  static Right = new Coordinate(1, 0);
  static Down = new Coordinate(0, 1);
  static Left = new Coordinate(-1, 0);
}

const { Up, Right, Down, Left } = Coordinate;

function move(direction: Coordinate) {
  // ...
}

move(Up);
move({ x: 1, y: 0 }); // Error (Property '#key' is missing...)
move(new Coordinate(1, 0)); // Error (Constructor of class 'Coordinate' is private)

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

Is it possible to modify a single value in a React useState holding an object while assigning a new value to the others?

In my current state, I have the following setup: const [clickColumn, setClickColumn] = useState({ name: 0, tasks: 0, partner: 0, riskFactor: 0, legalForm: 0, foundationYear: 0 }) Consider this scenario where I only want to update ...

Select three random items from a string array list along with their corresponding indexes using TypeScript in Angular

Consider this example: I am working with a string array const groceries = [ 'milk', 'coriander', 'cucumber', 'eggplant', 'carrot', 'brinjal', 'on ...

Angular component.html does not compile due to a check that includes inline array creation

There is an enum called Status: export enum Status { SOME_VAL = "SOME_VAL", SOME_VAL_2 = "SOME_VAL_2", SOME_VAL_3 = "SOME_VAL_3"; } Also, I have an interface named SomeInterface: export SomeInterface { status? ...

Attempting to add a new property to every object in an array using TypeScript

In my Angular project, I have a specific code block that retrieves an array of objects containing contact records. Within a 'forEach' loop, I am generating a new field for each contact record to store the user's initials. The goal is to ad ...

Tips on showcasing lengthy string content from JSON in a structured list format using react with typescript

Is there a way to display long string data from a JSON file in a list format when the description string is too lengthy? How can I split or format the description using React and TypeScript? The JSON data I have is as follows: "options": [ ...

Angular httpClient: Adjusting date format within json object

I need help converting the date property of an object to a format that the server can understand when using httpClient.post(...). Currently, the date property has its natural string representation. What steps can I take to make sure it is in the correct ...

The error "ReferenceError: window is not defined" occurs when calling client.join() due to

I am looking to create a video call application using React and Next.js with the AgoraRTC SDK. After successfully running AgoraRTC.createClient(), AgoraRTC.createStream(), and client.init(), I encountered an error when trying to execute client.join(). The ...

How to access the types of parameters in a function type

I am working on a function that takes a value and default value as arguments. If the value is a boolean, I want the return type to match the type of the default value. Here is the function I have: export type DetermineStyledValue<T> = ( value: str ...

What is the proper way to specify the type for a <video> element reference in React when utilizing Typescript?

I have been experimenting with controlling the play/pause state of a video in React.js using ref's. My code functions correctly but I am encountering tslint errors that I am currently trying to diagnose: function App() { const playVideo = (event:a ...

Matching utility types and themes in Tailwind CSS

I encountered an issue while trying to implement the Tailwind plugin in my project. It seems that a TypeScript error has occurred. I'm curious about the data types of matchUtilities and themes. Can someone provide some insight? const plugin = require( ...

Encountering an ExpressionChangedAfterItHasBeenCheckedError in Angular 6 when selecting an option from a dropdown menu

How can we fix the error mentioned below through code changes? Situation An input dropdown UI is safeguarded against unintentional value changes by a modal. However, triggering an event (such as click or focus) on the dropdown leads to the ExpressionChan ...

The bar chart functions perfectly on localhost but encounters issues after being hosted on Gitpage

Localhost Gitpage The bar chart was displaying correctly on localhost, but once it was hosted on Gitpage, it began to show issues. Any suggestions on how to resolve this? Repository Link: https://github.com/mzs21/bar-chart Live Preview: ...

Angular input box with integrated datepicker icons displayed inside

Currently, I have an input field and a datepicker displayed in a row. However, I need to show an icon inside the input box instead. Here is my code: <div class="mb-2" style=" float: left;" class="example-full-width" class= ...

The primary export is not a React Component on the specified page: "/"

Encountering an error while attempting to use compiled code from Typescript to Javascript with Next.js Error message: The default export is not a React Component in page: "/" Seeking assistance on how to resolve this issue. Any help would be greatly appr ...

The module "@clerk/nextjs/server" does not contain a member with the name "clerkMiddleware" available for export

Currently, I am working on Nextjs 14 with typescript and implementing authentication and authorization using Clerk. Following the instructions in the Clerk documentation, I included the code snippet below in my middleware.ts file: import { authMiddleware } ...

Data types for keys and values in TypeScript

interface A { a?: number }; interface B { a?: string }; function replicate< Source extends object, Destination extends { [key in keyof Source]?: (1) } >( source: Source, key: keyof Source, destination: Destination, converter: ...

Having trouble with the clip-path in d3.js liquid fill gauge

Attempting to integrate the d3.js liquid fill gauge into my angular2 webapp has been a challenge. The clippath functionality seems to be malfunctioning, resulting in no wave being generated at all. https://i.stack.imgur.com/3Bmga.png instead of https://i. ...

What is the best way to reference typescript files without using absolute paths?

As typescript does not seem to have built-in support for absolute path references (according to this GitHub issue), it becomes difficult to organize and maintain my file references. With TypeScript files scattered across various locations in my folder stru ...

Integrating Octokit middleware in Next.js for enhanced functionality

Currently, I am in the process of honing my skills by creating a GitHub app. In Octokit, there is a feature called createNodeMiddleware that caught my attention. However, integrating it with next.js seems to pose some challenges. My main issue right now re ...

Converting Angular 2/TypeScript classes into JSON format

I am currently working on creating a class that will enable sending a JSON object to a REST API. The JSON object that needs to be sent is as follows: { "libraryName": "temp", "triggerName": "trigger", "currentVersion": "1.3", "createdUser": "xyz", ...