Ensure the proper utilization of properties

Consider a scenario where I have a structure that defines a user along with their login and given name:

export interface User {
  login: string;
  name: string;
}

Now, my objective is to make an API call using the user's login information:

const formatLogin = (login: string) => login.toLowerCase().trim();
const fetchUser = (login: string) => ajax(`${API}/users/${formatLogin(login)}`);

Initially, calling getUser(this.user.name) seemed correct. However, this leads to an error, as it should be this.user.login. TypeScript doesn't raise any warnings due to them both being strings.

Is there a method in TypeScript to ensure that a specific property is utilized?

I attempted defining export type Username = string, but it was ineffectual since the name property still matches the criteria of a simple string. Similarly, creating an export interface Username {} failed to function correctly with the formatLogin function requiring string methods like toLowerCase and trim. Trying

interface Username extends String {}
presented the same issue.

Answer №1

One method involves the utilization of "branded types," as demonstrated in the TypeScript compiler's source code:

export type LoginString = string & { __loginBrand: any};

export interface User {
  login: LoginString;
  name: string;
}


const formatLogin = (login: string) => login.toLowerCase().trim();
const getUser = (login: LoginString) => { };

let user: User;

formatLogin(user.login); // successful
getUser(user.name); // error

To initialize a User object, one must manually cast an ordinary string to the LoginString type; providing an actual value for __loginBrand is not necessary, as it is solely for type validation.

Another suggestion offered by @estus is to utilize destructured objects as named parameters for an API. Although this approach lacks type checking, discrepancies are easily noticeable if all names are consistently used:

   export interface GetUser {
       login: string;
   }
   const getUser = ({login}: GetUser) => {}

   getUser(user); // successful
   getUser({login: user.name}); // unexpected result

Answer №2

The typing system cannot distinguish between these two properties because they are both random strings.

This is where test coverage plays a crucial role in reducing human errors.

Instead of relying solely on types, one can address the issue by adopting a logical method naming convention that minimizes room for mistakes. For instance, consider this error:

getUserByLogin(this.user.name);

such an error is more likely to stand out and be noticed.

Depending on the scenario, the getUser function could potentially take in an object reference instead of just a string, allowing it to extract the desired property from it:

getUser = ({ login }: User ) => ajax(`${API}/users/${formatLogin(login)}`);

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

Creating TypeScript Unions dependent on a nested object's property

I want to create a Union Type that is dependent on a nested property within my object. Take a look at the example provided below: type Foo = { abilities: { canManage: boolean } } type Bar = { abilities: { canManage: boolean ...

What are the best practices for integrating PrimeVue with CustomElements?

Recently, I decided to incorporate PrimeVue and PrimeFlex into my Vue 3 custom Element. To achieve this, I created a Component using the .ce.vue extension for the sfc mode and utilized defineCustomElement along with customElements.define to compile it as a ...

I am encountering an issue where my application is not recognizing the angular material/dialog module. What steps can I take to resolve this issue and ensure that it functions properly?

For my Angular application, I am trying to incorporate two Material UI components - MatDialog and MatDialogConfig. However, it seems like there might be an issue with the placement of these modules as all other modules are functioning correctly except fo ...

What is the process for creating a jQuery object in TypeScript for the `window` and `document` objects?

Is there a way to generate a jQuery object in TypeScript for the window and document? https://i.stack.imgur.com/fuItr.png ...

What is the best way to merge an array into a single object?

I have an array object structured like this. [ { "name": "name1", "type": "type1", "car": "car1", "speed": 1 }, { "name": &q ...

The specified property 'toString' is not found in the Typescript type

This particular situation was a bit perplexing for me. When I use the search function, I am seeking substring matches of the search keywords. Therefore, before comparing any object, I convert all properties to strings and check for substrings. Based on my ...

What is the best method for compressing and decompressing JSON data using PHP?

Just to clarify, I am not attempting to compress in PHP but rather on the client side, and then decompress in PHP. My goal is to compress a JSON array that includes 5 base64 images and some text before sending it to my PHP API. I have experimented with l ...

Looking to implement nested routes in Angular to ensure that each component's view updates properly

app-routing.module.ts import { NgModule } from '@angular/core'; import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; import { BreadcrumbComponent } from './main-layout/breadcrumb/breadcrumb.component'; im ...

Removing Angular Template space highlights in WebStorm can be done easily with a few simple steps

Is there a way to remove space highlights in Angular / TypeScript using WebStorm 2019? https://i.stack.imgur.com/vfudR.jpg Many thanks, Sean ...

Steps to create a TypeScript function that mimics a JavaScript function

As I look at this javascript code: // find the user User.findOne({ name: req.body.name }, function(err, user) { if (err) throw err; if (!user) { res.json({ success: false, message: 'Authentication failed. User not found.' ...

Trouble with using the date pipe in Angular specifically for the KHMER language

<span>{{ value | date: 'E, dd/MM/yyyy':undefined:languageCode }}</span> I am facing a challenge where I need to identify the specific locale code for the KHMER language used in Cambodia. Despite trying various cod ...

Encountering a NPM error when trying to launch the server using ng serve

I encountered an error : ERROR in /opt/NodeJS/FutureDMS/src/app/app.module.ts (5,9): Module '"/opt/NodeJS/FutureDMS/src/app/app.routing"' has no exported member 'APP_ROUTE'. Within my code, I have utilized arrow function in the loadCh ...

Error in Typescript SPFx: The property 'news' is not found in the type 'Readonly<{}>'

Currently, I am working on developing a spfx react component to showcase an RSS feed in the browser. My prototype is functional in a test environment, however, as spfx utilizes TypeScript, I am encountering a type error that I am unsure how to resolve. Rs ...

Guide for specifying type when passing a component as a prop

Struggling to successfully pass a component as a prop to a straightforward functional component called RenderRoute: interface RouteProps { component: React.ComponentType; isProtected: boolean; isLoggedIn: boolean; path?: string; exact?: boolean; ...

Is there a way to prevent QtLinguist from opening every time Visual Studio tries to display a TypeScript file?

Ever since I installed Qt tools for Visual Studio, my Ctrl+click on a class name triggers Qt Linguist: https://i.stack.imgur.com/USAH1.png This hinders me from checking type definitions, even though Visual Studio has already parsed them. The type informa ...

Can you explain the distinction between using [ngFor] or [ngForOf] in Angular 2?

From what I gather, both serve the same purpose. However, ngFor operates similar to collections. ngForOf functions more like generics. Am I correct in my understanding? Or can you provide more insight on the differences between ngFor and ngFor ...

What is the process for configuring the Authorization Header in ng2-signalr?

I am currently utilizing the library ng2-signalr within my ionic 2 project. I am facing an issue regarding setting the authorization header, as I have been unable to find any examples on how to do so. Below is my code snippet for establishing a connection ...

"Angular EventEmitter fails to return specified object, resulting in undefined

As I work on a school project, I've encountered a hurdle due to my lack of experience with Angular. My left-nav component includes multiple checkbox selections, and upon a user selecting one, an API call is made to retrieve all values for a specific " ...

Issue detected in TypeScript code - "Could not locate property 'setSelectedFile' in type 'void'.ts(2339)"

Encountering a TypeScript error in my code and seeking assistance. Below are the codes of 2 files with the error message included for review. The file causing the error is named "NewPostForm.tsx". import React, { useState } from 'react&apos ...

What is the best way to retrieve a value from async/await functions?

async function fetchNetworkStatus() { const network = await Network.getConnection(); setConnection(network.isConnected); console.log(connectionStatus); if (network.isConnected) { return true; } else { ...