What is the best approach for determining the correct type when an object property has a given prefix that is known in TypeScript?

Describing this concept can be a bit challenging, so let's jump straight into the code. Imagine I am working with strings that follow this specific format:

type ColumnName<
  Prefix extends string,
  Period extends 'month' | 'week'
> = `${Prefix}.${Period}`;`

For instance,

ColumnName<'dimension_date', 'month'>
would result in 'dimension_date.month'. Moving on,

type Month<Prefix extends string> = ColumnName<Prefix, 'month'>;
type Week<Prefix extends string> = ColumnName<Prefix, 'week'>;

Now, there's a function that accepts either a Month or a Week, along with a Prefix:

const get = <Prefix extends string>(
  column: Month<Prefix> | Week<Prefix>,
  prefix: Prefix
) => {
    const monthColumn: ColumnName<Prefix, 'month'> = `${prefix}.month`;

    if (column === monthColumn) {
      console.log(column); // The column is of type `${Prefix}.month`, as expected
    }
};

This function behaves correctly. However, my requirement is to have column as an object property:

type MonthObject<Prefix extends string> = { [K in Month<Prefix>]: number };
type WeekObject<Prefix extends string> = { [K in Week<Prefix>]: number };

const getObj = <Prefix extends string>(
  object: MonthObject<Prefix> | WeekObject<Prefix>,
  prefix: Prefix
) => {
    const monthColumn: ColumnName<Prefix, 'month'> = `${prefix}.month`;

    if (monthColumn in object) {
        console.log(object); // The object could potentially be of type MonthObject<Prefix> | WeekObject<Prefix>, but we expect it to only be of type MonthObject<Prefix>.
    }
}

Is there a way for TypeScript to know within the if statement that the type should exclusively be MonthObject<Prefix>?

Answer №1

A method can be utilized to validate the type.

const isMonth = 
    <Prefix extends string>(obj: MonthObject<Prefix> | WeekObject<Prefix>, prefix: Prefix)
        : obj is MonthObject<Prefix> => {
            const monthColumn: ColumnName<Prefix, 'month'> = `${prefix}.month`;
            return monthColumn in obj
}

This method can serve as the condition.

const getObj = <Prefix extends string>(
  object: MonthObject<Prefix> | WeekObject<Prefix>,
  prefix: Prefix
) => {
  if (isMonth(object, prefix)) {
    console.log(object);
    //          ^? (parameter) object: MonthObject<Prefix>

  }
}

link to 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

Looking for a way to dynamically append a child element within another child

Struggling to include a new child within a specific child in Json myObject:any[] = []; this.myObject = { "type": "object", "properties": { "first_name": { "type": "string" }, "last_name": { "type": "string" }, } } addF ...

Typescript struggles to identify properties that have no business being there

In my function for formatting data, the "values" contained within this data are clearly defined. However, TypeScript is failing to recognize new properties that are invalid when mapping these values. The issue can be best understood by looking at the code ...

Unable to retrieve route parameters in Angular 2

I have a scenario similar to this <a [routerLink]=" ['../projects', project.id] "> However, when attempting to retrieve a route parameter from the URL, I am not getting any results. Here is my import: import { Component} from '@ang ...

What is the process for an Angular Component to receive a return object from a service following an HTTP

I am currently working with angular 4. Is there a way to retrieve an object from a service in this framework? export class LoginRequest { username : string; password : string; } export class LoginResponse { token : string; message : string; sta ...

Issue with Angular Material Mat Horizontal Stepper: Incorrect step selection when progressing with next button

I have a horizontal mat stepper that needs to be controlled using Next and Back buttons. The steps are generated using ngFor. I have created a variable called "stepIndex" which is bound to the "selectedIndex" input. The Next button should increment this va ...

TypeScript error TS2305: The auth.service module does not contain a named export for 'AuthService'

When I was working on the routing and navigation code provided at https://angular.io/docs/ts/latest/guide/router.html. Using -- node v6.9.4 and npm v4.1.1, VSCode 1.8.1 IDE, Ubuntu 16.04 I encountered the following error: app/auth-guard.service.ts( ...

Exploring the best practices for utilizing the error prop and CSS with the Input API in Material UI while utilizing context

When working with the MUI Input API props and CSS, I encountered an issue related to the {error} and its use. This is how my code looks: const [value, setValue] = useState<string>(cell.value); const [startAdornment, setStartAdornment] = useState< ...

What could be preventing the array from updating after subscribing to the service?

Attempting to fetch a list of movies from a Web API server on my localhost. The server does provide data when called with a Get request using the HttpClient module, but struggling to display it. MovieList Component import { Component, OnInit } from &apos ...

Building basic objects in TypeScript

My current project involves utilizing an interface for vehicles. export interface Vehicle { IdNumber: number; isNew: boolean; contact: { firstName: string; lastName: string; cellPhoneNumber: number; ...

Managing quick mouse movements while resizing an element during a mousemove event

I'm seeking to implement a resizable modal that only adjusts its height. I've written some code, but when I attempt to extend it downwards quickly, it exceeds the element boundaries without any effect. I've come across codes that work proper ...

I am having an issue with the HttpInterceptor in my Angular7 application not functioning properly when errors occur. Can anyone help me troubleshoot the

I'm working on implementing multiple interceptors in my Angular7 project for tasks like authentication and error handling. However, I feel like I might be overlooking something simple and would appreciate a fresh set of eyes to help me spot any mistak ...

Combining multiple data types in an AJV array

Imagine you have the following defined type: type MixedArray = Array<number | string>; Now, let's say you have some sample data that needs to be validated: [ 'dfdf', 9, 0, 'sdfdsf' ] How can you create an Ajv JSONSchemeType ...

Uncover the content of a base64 encoded string and convert it into

A JSON response has been linked on the user's request to retrieve an excel document. The structure of the response is as follows: { "format": // file extn ----only xls "docTitle": //file name "document" :// base 64 encoded data } The attem ...

What is the best way to stay on track with internal anchor links when navigating with Aurelia?

I'm currently working on developing a style guide for a project and one of the features I would like to implement is a basic click behavior on anchor links, allowing them to smoothly scroll to the corresponding section on the page. For instance: < ...

Improving JavaScript Functions: Minimize duplication of helper methods

I have a set of helper functions that check for the presence of specific strings in an array and certain steps before triggering other functions. The reason for keeping them separated is because arrTours must be associated with only those arrSteps. // Help ...

typescript unable to establish a connection with postgres.SqlClient

My attempt to establish a connection with a postgresSQL database in typescript is not going smoothly. Unfortunately, I am encountering difficulties without a clear indication of the cause. Despite the absence of an error log output, I tried using manual c ...

Mapped TypeScript type requiring scalar properties and allowing optional objects

I am in need of a TypeScript generic type that has the capability to alter another type so that all scalar properties (such as strings, numbers, booleans, etc.) remain mandatory, while object types become optional. For instance, given the User type below, ...

Unlocking new perspectives with a click

Currently exploring Angular development, I have encountered a question here but couldn't find the solution I was looking for. I am seeking suggestions and ideas on how to approach this issue. Essentially, my HTML includes buttons like the ones shown ...

Utilize API with unique characters in the URL

Attempting to make an API call from the front end using this API: http://localhost/search?userName=... get(endpoint: string, responseType = 'json', params: HttpParams = null): Observable<any> { let url = this.getHost() + endpoint; i ...

Is there a convenient feature in WebStorm for quickly inserting a lambda function in TypeScript that matches the current argument's signature while coding?

While working with promise chains in TypeScript, I often find myself dealing with a syntax tax that can become cumbersome. It would be great to have a way to automate this process, especially when using WebStorm. My ideal situation would involve having an ...