Distinguish between two varieties using parameters

Let's consider the following simplified example:

type Reference<T extends {identifier: string}> = T['identifier']

In this type, TypeScript recognizes that it is a reference to an object where the identifier property is of type string. However, how can we make TypeScript treat two different identifiers as distinct strings?

For example, if we have the following incorrect assignment:

let blogRef: Reference<Blog> = ...
let userRef: Reference<User> = ...

// TypeScript allows this even though they are both strings:
blogRef = userRef

This is logically incorrect. Is there a way to enforce this as a compile-time check in TypeScript?

Answer №1

type simply creates a type alias for another type. In this scenario, both Ref<Blog> and Ref<User> are essentially the same as the type string, making them fully interchangeable.

To make differently branded strings (or any type) incompatible, you can utilize branded types. These types leverage TypeScript's method of determining type compatibility (structural compatibility):

class Blog {
    id: string  & { brand: 'blog' }
}

class User {
    id: string  & { brand: 'user' }
}

type Ref<T extends {id: string}> = T['id']

function createUserId(id: string) : Ref<User> {
    return id as any
}

function createBlogId(id: string) : Ref<Blog> {
    return id as any
}

let refBlog: Ref<Blog> = createBlogId("1");
let refUser: Ref<User> = createUserId("1");


refBlog = refUser // error 

You will need to define helper functions that generate instances of the types or use type casting, but with this approach, the types will be incompatible.

This article delves further into this topic. Additionally, the TypeScript compiler employs this strategy for handling paths.

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

Trouble with Typescript in VSCode made easy

Setting up a VSCode environment for working with TypeScript v2.03 has been challenging. Beginning with a simple vanilla javascript snippet that can be tested in node via the integrated terminal. function Person() { this.name = ""; } Person.prototy ...

Is there a way to duplicate the method signature and apply it to a different method?

I came across a library that contains the following class: class Dog { public run(speed: number, movement: number): void; public run(speed: number, type: string): void; public run(speed: number, opts: string | number): void { // performing some a ...

What is the best method for transferring chosen items to a different multiple select using Angular?

How can I transfer selected items to another list, in order to manipulate the final object/array later on? student.component.ts: students= []; studentsFinal = []; onGetStudents() { this.studentService.getStudents() .subscribe( (s ...

What is the best way to track events in angular-meteor when a user logs in, logs out, or when there is a change in the user

I am working on meteor-angular and trying to track new user login and logout changes within a single component. I have attempted to subscribe to userData in the component's initialization, but it does not seem to detect when the user logs in or out. I ...

Transforming TypeScript snapshot data in Firebase Cloud Functions into a string format for notification purposes

I've encountered the following code for cloud functions, which is intended to send a notification to the user upon the creation of a new follower. However, I'm facing an issue regarding converting the snap into a string in order to address the er ...

What is the best way to create an array of strings that can include multiple elements from a set of strings?

Exploring different roles for authorization: ['admin', 'manager', 'user'] Is there a way to create a specific type, named Roles, which is essentially a string array ( string[] ) that is limited to only containing values from ...

The setInterval function continues executing even after the page has been changed

I'm encountering an issue with my function where it continues to run even after the page has changed, resulting in an error. How can I go about stopping this behavior? Thank you! componentDidMount() { var current = 0; var slides = document.g ...

When the child component's form is marked as dirty, the parent component can access it

I have implemented a feature in my application that notifies users about pending changes on a form before they navigate away. Everything works as expected, but I have a child component with its own form that needs to be accessed by the guard to check if i ...

TS1057: It is required that an async function or method has a return type that can be awaited

There was a recent Github issue reported on March 28th regarding async arrow functions generating faulty code when targeting ES5, resulting in the error message: TS1057: An async function or method must have a valid awaitable return type You can find t ...

Is it possible to use square brackets in conjunction with the "this" keyword to access a class property using an expression?

export class AppComponent implements OnInit { userSubmitted = false; accountSubmitted = false; userForm!: FormGroup; ngOnInit(): void {} onSubmit(type: string): void { this[type + 'Submitted'] = true; if(this[type + 'For ...

Detecting the language of a browser

In my Angular2 application, I am looking to identify the browser language and use that information to send a request to the backend REST API with localization settings and variable IDs that require translation. Once the request is processed, I will receive ...

How can I implement a dynamic progress bar using Ionic 4?

I am currently working on developing a progress bar that increases by 1% every time the user clicks a button. This is what my HTML code looks like: <ion-button *ngFor="let progress of progress" (click)="add(progress)">Progress</ion-button> &l ...

Utilizing the Filter Function to Eliminate an Element from an Array

I am a beginner in the world of React and I'm currently working on developing a simple timesheet tool where users can add tasks and save them. My tech stack includes React and Typescript. Currently, my main component has an empty array for tasks and ...

What is the recommended TypeScript type to be returned from a GraphQL resolver when using ESLint?

Repository Link https://github.com/inspiraller/apollo-typescript The code is functioning correctly, however, Eslint typescript is raising complaints. An eslint error occurs on the following code block: Query: { players: () => players } Miss ...

Issue regarding retrieving the image using TypeScript from an external API

Hey developers! I'm facing an issue with importing images from an external API. I used the tag: <img src = {photos [0] .src} /> but it doesn't seem to recognize the .src property. Can anyone shed some light on how this is supposed to work? ...

Is there a way to dynamically change an icon based on certain conditions using typescript?

I am struggling with displaying icons in my TypeScript code using Material Icons. I need to dynamically change the icon based on a condition, for example if the power is false I want to display 'power_off', but if it's true then I want to di ...

Is there a way to transform a complex nested class object into a simple object without losing its methods

Is there a way to convert a deeply nested class object into a plain Object type while still retaining methods like getters and setters? class A { id = ""; data = { sync: {} }; } class SyncService { syncResultServiceA = { ...

Improving the management of user input in Lit components

I am seeking a more efficient method to manage all inputs within my lit component while minimizing the code usage. I am also employing Typescript in this process, utilizing @change=${this.handleInput} for all input fields. Below is an example of how the ha ...

Angular 7: Polyfill required for npm package to support 'Class'

I am encountering an issue where my Angular 7-based app is not functioning in Internet Explorer 11. The npm package I am using begins in index.js: class PackageClass { // code } While the app works as intended in other browsers, it fails to open in ...

What is the reason behind typescript making it necessary for me to find a way to set a value of type

function f1() { const v : string = String(); if(v) {alert("IF");} // OK const b : boolean = v; // Type 'string' is not assignable to type 'boolean'. if(b) {alert("BOOLEAN");} } f1(); My approach to this issue involv ...