Comparison between a string and a union of two literal types is permitted

How come this code is able to compile?

type EntityType = "x" | "y"

type myFunc = (id: number, categoryType: EntityType) => void

const x: myFunc = (id: number, categoryType: string) => {
    // some code here
}

Is there a way to make sure myFunc only accepts "x" or "y"?

UPDATE:

Based on the previous information, it seems like we can assign typeX to typeY where typeY includes all of typeX's values.

Why does the compiler show an error message like this?

Type 'string' is not assignable to type 'EntityType'

type EntityType = "x" | "y"

const someString: string = "x"

const x: EntityType = someString

The error above is exactly what I was expecting for the initial code snippet.

Answer №1

It is possible to assign a function that can handle a wider range of values to a function that can handle only a limited subset of those values because the RHS function can safely deal with the restricted set of values accepted by the LHS function.

type EntityType = "x" | "y"

type myFunc = (id: number, categoryType: EntityType) => void

const x: myFunc = (id: number, categoryType: string) => {
    // some code here
}

x(1, 'x')
x(2, 'y')
x(3, 'a') // error

TS playground


Answer to updated question:

Based on the example above, it may seem like we can assign typeX to typeY if typeY includes all elements of typeX.

In short: no, this is not allowed.

Assignment only works when the RHS type is a subtype of the LHS type. For functions, this principle applies as well. Functions have two types and are contravariant in their argument type while being covariant in their return type. This behavior is determined by variance. Thus, for functions, subtyping follows these rules:

type Fn1 = (arg1: Arg1) => Ret1
type Fn2 = (arg2: Arg2) => Ret2
Fn1 extends Fn2 // implies const fn2: Fn2 = fn1 as Fn1
  <=> // if and only if
(arg1: Arg1) => Ret1 extends (arg2: Arg2) => Ret2
  <=>
Ret1 extends Ret2 'and' Arg2 extends Arg1

The relationship between argument types goes in the opposite direction, allowing assignment only when encountered in the argument's position. However, this does not permit types to be directly assignable like plain values. The contravariant direction only holds true within arguments.

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

unable to reinstall due to removal of global typing

After globally installing Moment typing with the command typings install dt~moment --save --global Checking the installed typings using typings list shows: ├── <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="93fffcf7f2e0 ...

Translating a C# ViewModel into TypeScript

Here is a C# viewmodel example: public class LoginModel { [Required(ErrorMessage = "Email is not specified")] public string Email { get; set; } [Required(ErrorMessage = "No password is specified")] [DataType(DataType.Password)] public ...

What are the steps to implement cp-react-tree-table in my application?

Recently diving into TypeScript, I decided to explore the demo provided by https://www.npmjs.com/package/cp-react-tree-table in order to incorporate this control into my project. However, I encountered some unexpected information. After conducting a thoro ...

What is the reason behind the NgForOf directive in Angular not supporting union types?

Within my component, I have defined a property array as follows: array: number[] | string[] = ['1', '2']; In the template, I am using ngFor to iterate over the elements of this array: <div *ngFor="let element of array"> ...

I'm struggling with finding an answer to this question: "What is the most effective way to conduct a

I'm experimenting with a file upload. I decided to encapsulate the FileReader() inside an observable based on information I found in this discussion thread: onFileSelected(event: any) { this.importJsonFileToString(event.target.files[0]) .p ...

Utilize string values as identifiers in type declarations

My Props type declaration currently looks like this: type Props<FormData> = { formData: FormData, sectionNme: keyof FormData, name: string } However, I am trying to modify it to look more like the following: type Props<FormData> = ...

Creating a global variable using Typescript in AngularJS components

Within my application, I have been utilizing components and a boostrapper. The main goal is to implement a datepicker that can set a global date variable. Despite exploring various options such as creating a service, utilizing rootscope, and researching so ...

The Angular framework is unable to locate a differ that supports the object '[object Object]' which is of type 'object'

In my Angular project, I am calling an API and receiving the following JSON data: { "id": 16, "poste": "ameur taboui", "desciption": "f", "service": "f", ...

How can I convert an object to JSON using JSON.stringify and ensure its type is recognized as JSON?

When I attempt the following code snippet: import { MyType } from 'somewhere'; class MyClass { myObj: MyType = new MyType(); updateObject(newVal: string): void { myObj.thing = newVal; this.saveStuff(JSON.stringify(myObj ...

Executing numerous API requests through ngrx effect

I am still learning about the ngrx store and redux pattern. I've encountered an issue with dispatching the updatePresentation$ effect. This effect is triggered when the updatePresentation action is invoked. Here's how the updatePresentation actio ...

What is the process of including types in a Vite library build?

After following the documentation on Vite for implementing library mode, I successfully created a functional component library. Utilizing the vue-ts preset, I defined props with their respective types and utilized interfaces within my components. However ...

SQLite - executing multiple calls within a single transaction

Greetings, I am currently working on developing a front end Single Page Application (SPA) using Typescript. I have chosen to utilize capacitorJS for cross-platform compatibility and have integrated the @capacitor-community/sqlite plugin into my project. Wh ...

What causes the Cassandra client driver to provide more detailed information compared to cqlsh?

I'm currently utilizing the datastax nodejs-driver to retrieve information about a keyspace from cassandra. const results = await client.execute( ` DESC KEYSPACE ${keyspace} ` ); The method client.execute provides a comprehensive object containin ...

Global Inertia Headers

How can I ensure that a custom header (Accept-Content-Language) is sent with every request, including Inertia manual visits? Below is the code snippet where I define and set the header: import axios from 'axios'; const lang = localStorage.getIt ...

How can TypeScript handle unresolved generics within conditionals using "catch"?

For quite some time now, I've been on the quest to find a real-life example that isn't overly complex for this scenario. Let's see if this one fits the bill. The context here relates to our usage of immer, which provides a Draft type struct ...

Maintaining search filters across pages in Angular 2 using URL parameters

I am attempting to store certain filters in the URL for my application, so that they can be reapplied when the page is reloaded. I am encountering challenges with Dates (using moment), nullable properties, and special characters (/). When I pass values to ...

Switching the focus of detection from a child to a parent

I am currently working on enhancing the functionality of my UI to display selections dynamically as they are selected or de-selected. import { Wizard } from './report-common'; import { Router } from '@angular/router'; import { DataServ ...

Substitute data types for certain keys within a Typescript interface

Within this code snippet, the goal is to create a new type from an existing one by iterating through the keys and only replacing those that meet a specific condition. Additionally, union types are being utilized here. class A {} class B { constructor ...

What is the best method for incorporating an Angular Component within a CSS grid layout?

I recently started learning Angular and am currently working on a project that requires the use of a CSS grid layout. However, I'm facing an issue with inserting a component inside a grid area specified by grid-area. My attempt to achieve this in app ...

What is the best way to save data from a Firebaselistobservable into an array?

I've been attempting to transfer data from Firebase to an array using Angular 2, but I'm facing difficulties in pushing the data into the array. Below is the code snippet: Variables: uid: string = ''; agencyItems: FirebaseListObserva ...