Getting the Final Character from a TypeScript String Constant

Can we extract the final character from a string without using the entire alphabet as an enum? Right now, I'm focusing on numeric digits.

I'm somewhat puzzled about why my current approach isn't yielding the correct results.

type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';

type GetFirstDigitOfStringLiteralNumber<T extends `${string}${Digit}`> = T extends `${infer D extends Digit}${string}` ? D : never;
type GetLastDigitOfStringLiteralNumber<T extends `${string}${Digit}`> = T extends `${string}${infer D extends Digit}` ? D : never;

// This is accurate
type FirstCharacter = GetFirstDigitOfStringLiteralNumber<"21222">;
//    ^? "2"
// This is accurate
type LastCharacter1 = GetLastDigitOfStringLiteralNumber<"12">;
//    ^? "2"
// This is incorrect
type LastCharacter2 = GetLastDigitOfStringLiteralNumber<"21222">;
//    ^? '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

Playground

The issue with `LastChracter2` not functioning correctly surprises me. My assumption is that TypeScript struggles to identify the `${string}` portion accurately and thus stops analyzing static data due to this limitation.

However, it remains unclear why the system doesn't default to returning `never` when unable to match the `Digit` portion to a specific character.

Edit:

Assigning a name to the inferred `${string}` section appears to produce the `never` outcome I originally anticipated, even though no other changes were made:


type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';

type GetLastDigitOfStringLiteralNumber<T extends `${string}${Digit}`> = T extends `${infer L extends string}${infer D extends Digit}` ? D : never;

// This works fine
type InferLeading = GetLastDigitOfStringLiteralNumber<"12">;
//    ^? "2"

// Why does this fail?
type InferLeading2 = GetLastDigitOfStringLiteralNumber<"112">;
//      ^? never

Answer №1

The issue at hand arises from using ${infer L}${infer R} on a string that exceeds two characters in length. In such cases, the inference will designate the first character as L and the rest as R. For example, with the input "123456", L would be "1" and R would be "23456". This approach leads to incorrect results when checking if R extends Digit where R is more than one character.

To rectify this issue, one can introduce recursion into the type declaration.

type GetLastDigitOfStringLiteralNumber<T extends `${string}${Digit}`> = 
  T extends `${string}${infer REST extends `${infer L}${Digit}`}` 
    ? GetLastDigitOfStringLiteralNumber<REST> 
    : T

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

"Enhance your Vue 3 project with TypeScript and take advantage of smart template suggestions

Is it feasible to enable autocompletion/suggestions in the template section of a Single File Component (SFC) when using VS Code with Vue 3 and Typescript, particularly for component props? For instance, consider a basic component named UserComponent: < ...

Attempting to eliminate any dates that have already occurred

I am faced with an array containing various dates in string format such as "2016-08-12". My goal is to eliminate any dates that have already passed by comparing them to today's date. I am using TypeScript for this task. Here is a snippet of my datoAr ...

Grouping elements of an array of objects in JavaScript

I've been struggling to categorize elements with similar values in the array for quite some time, but I seem to be stuck Array: list = [ {id: "0", created_at: "foo1", value: "35"}, {id: "1", created_at: "foo1", value: "26"}, {id: "2", cr ...

The class instances are not invoking the decorators

I'm experiencing issues with my decorators. It seems that the decorators are not being invoked on every instance of the class. While I understand that decorators are called during declaration time, I am wondering if there is a way to call them for eac ...

TypeORM Error: Trying to access property 'findOne' of an undefined object

I've been working on implementing TypeORM with Typescript, and I have encountered an issue while trying to create a service that extends the TypeORM repository: export class UserService extends Repository<User> { // ... other service methods ...

Asynchronously download static images with the power of NextJS and TypeScript integration

I have a query regarding my website development using NextJS and TypeScript. The site features a showcase gallery and is completely static. Currently, the initial view shows thumbnails of images. When clicking on a thumbnail, the original image is display ...

Typescript displays an error message when attempting to assign a list of string variants to a defined type

Encountering an interesting TS error in the code snippet below: interface Bar { pictureType: "X" | "Y" } interface RT { output: Bar[] } const func = (): RT => { const list = [{ pictureType: 'X', }] r ...

The lazy loading feature in Angular 12 is not functioning correctly for path modules

My application has a jobs module with various components, and I'm trying to lazy load it. However, I've encountered an issue where accessing the module through the full path http://localhost:4200/job/artist doesn't work, but accessing it thr ...

Retrieve information from a URL to transmit to a different page in NextJS using Typescript and AppRouter

I'm struggling with transitioning from the Home page to the Detail page. I've successfully passed data to the URL from the Home screen, but I'm having trouble accessing it in the Detail screen. I'm working with NextJS ver 13, using Type ...

The selectors in NgRx store are failing to retrieve data from the main global store

As I delve into the world of ngrx, I find myself struggling to fully understand and implement it effectively within my application. Recently, I integrated ngrx version 8.3 into my project in hopes of organizing my state management efficiently. My goal is ...

Comparison between typings and @types in the NPM scope

There are different approaches when it comes to handling TypeScript definitions. In some cases, the typings tool is used, as seen in projects like angular/angular2-seed. Alternatively, some projects use scoped NPM packages with the prefix @types, complete ...

Retrieving Information from an Angular 2 Component

Struggling to figure this out, I am attempting to dynamically add user video data that includes a video URL. My goal is to access the data from the component so I can use it in my HTML. I've attempted the following approach. app.component.ts import ...

Prohibit the use of explicit type parameters or limit the union type parameters to enhance the safety of the types

When the getValues() function is called without explicit type parameters, the Typescript code functions correctly. However, calling it with explicit type parameters can result in errors (as seen in invocation getValues<'a' | 'b' | &a ...

When utilizing a generic type with a class, type T fails to meet the specified constraint

export type ExtractType<T extends Array<{ name: Array<string>, type: keyof TypeMapping }>> = { [K in T[number]['name'][0]]: TypeMapping[Extract<T[number], { name: K }>['type']] } export class CommandLineParse ...

Template reference does not connect to the ApexChart graphic

As a newcomer to ApexCharts.js, I am currently working on setting up a Vue3 app using Composition API along with the setup syntax. My goal is to reference the template ref of 'apexchart' so that I can later call the dataURI() function on it. I am ...

Content obscuring dropdown menu

I am currently working on a screen design that resembles the following: return ( <SafeAreaView> <View style={styles.container}> <View style={styles.topContainer}> <View style={styles.searchFieldContainer}> ...

Sequencing API Calls: A Guide on Making Sequential API Requests

Currently, I am working on mastering RxJS. Within my project, there are 3 API calls that need to be made. Specifically, I must execute the 2nd API call and then pass its data as a parameter to the 3rd API call. My attempt at achieving this functionality is ...

"Enhance your PrimeVue Tree component with interactive action buttons placed on every TreeNode

Details: Using Vue 3.3.6 in composition API script setup style Utilizing PrimeVue 3.37.0 and PrimeFlex 3.3.1 Implemented with Typescript Objective: To create a tree structure with checkboxes that are selectable, along with action buttons on each TreeNod ...

The child component is failing to detect changes, consider using alternative methods like ngDoCheck to update the component's value

Within the childComponent @input() method, I am sending an array of objects where each object has 3 properties: name, id, and selected (boolean). My goal is to change only the selected property in the array and pass it to the child component for rendering. ...

Tips on retrieving a strongly typed value from a method using Map<string, object>

Having had experience working with C# for a while, I recently ventured into a Node.js project using TypeScript V3.1.6. It was exciting to discover that TypeScript now supports generics, something I thought I would miss from my C# days. In my C# code, I ha ...