Expanding a TypeScript type by creating an alias for a property

I am working on defining a type that allows its properties to be "aliased" with another name.

type TTitle: string;
type Data<SomethingHere> = {
  id: string,
  title: TTitle,
  owner: TPerson,
}

type ExtendedData = Data<{cardTitle: "title", author: "owner"}>;  // or any other way to define this type

Now, ExtendedData is transformed into a type as follows:

type ExtendedData = {
  id: string,
  title: TTitle,
  cardTitle: TTitle,
  owner: Person,
  author: Person,
}

My goal is to explain a graphQL query response which contains aliased fields, clearly showing that cardTitle is an alias of title and carries the same type.

Answer №1

Incorporating a custom type called ExtendWithAlias, I have designed it to accept two generic arguments: the base type (

T extends Record<PropertyKey, any>
) and an object (
A extends { [aliasName: PropertyKey]: keyof T }
) that will enhance the base type by utilizing an Intersection Type.
By leveraging a Mapped Type with Key Mapping and a Conditional Type, we can "look up" an existing keyof T (= keyof Data) and include it in our newly computed type with a specified alias. It should be noted that TypeScript will automatically infer TTitle as string.

One thing to keep in mind is that I have only tested this implementation with your specific input and some basic variations. There may be potential flaws or limitations when dealing with more intricate, nested types.

type TTitle = string;
type Data = {
  id: string;
  title: TTitle;
};

type ExtendWithAlias<
  T extends Record<PropertyKey, any>,
  A extends { [aliasName: PropertyKey]: keyof T },
> = T & {
  [K in keyof A as A[K] extends keyof T ? K : never]: T[A[K]]  
};

type ExtendedData = ExtendWithAlias<Data, { cardTitle: "title" }>;
// type ExtendedData = Data & {
//     cardTitle: string;
// }

Further testing:

type Invalid1 = ExtendWithAlias<Data, { cardTitle: "no title" }>;
//                                    ~~~~~~~~~~~~~~~~~~~~~~~~~
// Type '{ cardTitle: "no title"; }' does not satisfy the constraint ...
type Invalid2 = ExtendWithAlias<Data, { cardTitle: {} }>;
//                                    ~~~~~~~~~~~~~~~~~
// Type '{ cardTitle: {}; }' does not satisfy the constraint ...

type ValidMultiple = ExtendWithAlias<Data, { cardTitle: "title", idAlias: "id" }>;
// type ExtendedData4 = Data & {
//     cardTitle: string;
//     idAlias: string;
// }

TypeScript 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

error: encountering issue with Vue TypeScript Jest tests - '$store' property is undefined

I've been facing issues with my tests failing after a recent npm install. I've tried adjusting versions up and down, but haven't had any success. Interestingly, the $store isn't directly used in any of the components or tests. Despit ...

A step-by-step guide to showcasing dates in HTML with Angular

I have set up two datepickers in my HTML file using bootstrap and I am attempting to display a message that shows the period between the first selected date and the second selected date. The typescript class is as follows: export class Datepicker { ...

Is it possible to utilize class as generics in passing?

I recently started working with Java generics and came across a confusing situation while trying to pass a generics class as an argument to a method. In my Android project, I used the Volley library to handle server calls. Below is the code snippet: Advan ...

`How can I stop typescript from converting dynamic imports to require()?`

Currently, I am in the process of creating a Discord bot using discord.js. Interestingly, discord.js does not seem to be compatible with ESM modules, which has been causing some complications in my project. As a result, I have resorted to utilizing CommonJ ...

The pipe property cannot be accessed for the specified type "OperatorFunction<unknown, [unknown, boolean, any]>"

I have set up a data subscription that I want to utilize through piping, but for some reason it's not working as expected. The error message I'm receiving is: The property pipe is not available for type "OperatorFunction<unknown, [unknown, b ...

In the production mode, Webpack doesn't compile any code

I recently followed the typescript guide at https://webpack.js.org/guides/typescript/ After running webpack in "production" mode, I noticed that it emitted very minimal output. Below is the code from my src/index.ts file: export function foo() { return ...

Error encountered in Snap SVG combined with Typescript and Webpack: "Encountered the error 'Cannot read property 'on' of undefined'"

I am currently working on an Angular 4 app that utilizes Snap SVG, but I keep encountering the frustrating webpack issue "Cannot read property 'on' of undefined". One solution I found is to use snapsvg-cjs, however, this means losing out on the ...

A versatile Material UI paper that adjusts its dimensions dynamically

Utilizing Material-UI's Paper component (https://mui.com/components/paper/), I've encountered a scenario where the content within the Paper element needs to be dynamic. <Paper className="modal" elevation={3}> ...Content </Paper ...

Struggling with setting up a search bar for infinite scrolling content

After dedicating a significant amount of time to solving the puzzle of integrating infinite scroll with a search bar in Angular, I encountered an issue. I am currently using Angular 9 and ngx-infinite-scroll for achieving infinity scrolling functionality. ...

Initiating the ngOnInit lifecycle hook in child components within Angular

I am facing an issue with controlling the behavior of child components in my Angular application. The problem arises when switching between different labels, causing the ngOnInit lifecycle hook of the children components not to trigger. The main component ...

React dynamic table

I've been experimenting with creating a dynamic table in React that allows users to add and delete rows. I need the data entered by the user to be saved, possibly using in-state management so that I can work with it later. Essentially, I'm looki ...

Type inference error in TypeScript occurs within a conditional statement when the condition relies on the output of a function call rather than a boolean expression

In my TypeScript code, I have a Linked List class that is working perfectly. The class includes a Node type and functions to add items to the list. type ListItem = number | string | object; class Node { private value: ListItem; private next: Node | nu ...

Why is the Last Page display on pagination showing as 3 instead of 2 per items?

When working on Angular 13, I encountered an issue with applying pagination numbers like 1, 2, 3, etc. The problem I faced was that the last page Number should be 2, but it is displaying as 3. Why is this happening? To investigate the issue, I tested my ...

Whenever I try to load the page and access the p-tableHeaderCheckbox in Angular (primeng), the checkbox appears to be disabled and I am unable to

I attempted to use the disabled attribute on p-tableheadercheckbox in order to activate the checkbox. <p-tableHeaderCheckbox [disabled]="false"></p-tableHeaderCheckbox> <ng-template pTemplate="header"> <tr> ...

Troubleshooting problem in Grunt-TS, Grunt, watch/compile, and Dropbox integration

UPDATE: Recently, I've been experiencing some issues with another computer when it comes to watching and compiling. It seems like the tscommandxxxxxx.tmp.txt files that are generated during compilation might be causing the trouble... sometimes they ar ...

How do I inform Jest that spaces should be recognized as spaces?

Here is some code snippet for you to ponder: import { getLocale } from './locale'; export const euro = (priceData: number): string => { const priceFormatter = new Intl.NumberFormat(getLocale(), { style: 'currency', currenc ...

Error: 'process' is not defined in this TypeScript environment

Encountering a typescript error while setting up a new project with express+ typescript - unable to find the name 'process'https://i.stack.imgur.com/gyIq0.png package.json "dependencies": { "express": "^4.16.4", "nodemon": "^1.18.7", ...

Error in AWS Lambda: Module 'index' not found

In my setup, I have kept it simple by using typescript. All my typescript files are compiled into a /dist directory. Debugging with Webstorm is smooth as it easily finds the handler: https://i.sstatic.net/qkxfD.png The problem arises when I try to run i ...

Is it possible to assign an alternative name for the 'require' function in JavaScript?

To ensure our node module is executable and includes dependencies for requiring modules at runtime, we utilize the following syntax: const cust_namespace = <bin>_require('custom-namespace'); This allows our runtime environment to internal ...

What is the method to remove curly brackets from a different data category?

If I have a type like this type Z = {a: number} | {} | {b: boolean} | {c: string} | ...; Is there a way to get the same type but without {}? type Y = Exclude<Z, {}>; ⇧This will result in Y = never, because all variants can be assigned to {} and a ...