When passing a property name via generic, it is not possible to have multiple properties

I recently came across a coding example that I found interesting:

export type TimeStamped<TContent, TContentName extends string> = {
    [P in TContentName]: TContent
}

type Food = 'apple' | 'banana' | 'pear'
type TimeStampedFood = TimeStamped<Food, 'food'>

type Animal = 'cat' | 'dog' | 'horse'
type TimeStampedAnimal = TimeStamped<Animal, 'animal'>

const banana: TimeStampedFood = {food: 'banana'}
const cat: TimeStampedAnimal = {animal: 'cat'}

console.log(banana, cat)

While the above example is functional, I decided to enhance it by adding creation and expiry date tracking for these objects, as shown below:

export type TimeStamped<TContent, TContentName extends string> = {
    [P in TContentName]: TContent,
    createdAt: DateTimeString,
    expiresAt?: DateTimeString
}

type Food = 'apple' | 'banana' | 'pear'
type TimeStampedFood = TimeStamped<Food, 'food'>

type Animal = 'cat' | 'dog' | 'horse'
type TimeStampedAnimal = TimeStamped<Animal, 'animal'>

const banana: TimeStampedFood = {
    food: 'banana',
    createdAt: '2020-01-01T00:00:00Z',
    expiresAt: '2020-01-01T01:00:00Z'
}
const cat: TimeStampedAnimal = {
    animal: 'cat',
    createdAt: '2016-01-01T00:00:00Z',
    expiresAt: '2023-01-01T01:00:00Z'
}

console.log(`The ${banana.food} expires at ${banana.expiresAt}`)

However, I encountered some errors while trying to define properties dynamically within the object:

Expecting newline or semicolon
Unnecessary label 'createdAt' 
TS2304: Cannot find name 'expiresAt'
TS1128: Declaration or statement expected.

I'm looking for a way to have an object with createdAt and optionally expiresAt properties defined, while allowing flexibility in naming the content property. Do you know of a solution for this issue?

Answer №1

It is not advisable to proceed in that manner, please refer to this link for more information on how to combine known interface properties with a custom index signature.

You can also check the official documentation for guidance: here

Consider exploring some of these alternatives:

export interface TimeStamped {
    createdAt: DateTimeString;
    expiresAt: DateTimeString;
}

type Food = 'apple' | 'banana' | 'pear'
type TimeStampedFood = { food: Food; } & TimeStamped;
// Additional reference: https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types

type Animal = 'cat' | 'dog' | 'horse'
interface TimeStampedAnimal extends TimeStamped {
     animal: Animal; 
}
// More details available at: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#interfaces

const banana: TimeStampedFood = {
    food: 'banana',
    createdAt: '2020-01-01T00:00:00Z',
    expiresAt: '2020-01-01T01:00:00Z'
}
const cat: TimeStampedAnimal = {
    animal: 'cat',
    createdAt: '2016-01-01T00:00:00Z',
    expiresAt: '2023-01-01T01:00:00Z'
}

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

The 'errorReason' property is not found within the 'MessageWithMdEnforced' type

I am currently working on a project using meteor, react, and typescript. Here is the section of code that is causing an error: {message?.errorReason && <div>{message?.errorReason}</div> } The error message I am encountering is: "P ...

Make the if statement easier - Angular

Would you like to know a more efficient way to streamline this If statement? The variables are all strings and are reused in both conditions, but the outcome varies depending on whether it returns true or false. if(params.province && !params.str ...

Page loading causing sluggishness in Angular application

I've been encountering this problem for quite some time now and have searched extensively online for solutions. However, I believe I may not be using the correct terminology to accurately pinpoint the issue. Within my package.json, I have included th ...

Special react-hook designed for dynamically assigning CSS classes

I'm currently exploring React's hooks and playing around with reusing the ability to add a shadow to an element (utilizing bootstrap as the css-framework). Here is the current structure of my App: export const App: React.FunctionComponent<IA ...

Exploring the Power of Angular's Redux Implementation with Lazy Loading Strategy

Implementing Redux with Angular has been incredibly beneficial for me, but I am curious about how lazy loading can be incorporated alongside it. Can these two techniques work well together? ...

Utilize TypeScript Generics to define an object with a different type specified for its key and value

I'm encountering some challenges when working with Generics in TypeScript. My goal is to create an object based on another object type using Generics. I initially referenced this TypeScript documentation This is the code snippet I have come up with ...

Conceal mat-table column when form field is empty

As a newcomer to the world of programming, I am currently tackling a table that includes form fields for filtering purposes. My goal is to dynamically hide or show table columns based on whether a form field has a value or not. In my table.component.ts ...

typescript error in navigating with parameters

Having trouble adding a param with TypeScript and encountering the following error: Error: Argument of type '["Profile", { screen: Screen; }]' is not assignable to parameter of type '[screen: "Explore"] | [screen: "E ...

Breaking up and Substituting text within Angular 8's HTML structure

When I retrieve data from a REST api, I need to split the name parameter at '2330' and insert a line break. For example, if the name is: ABCD 2330 This is My Name, I want the output on my screen to appear as: ABCD 2330 This is My Name // this par ...

Obtaining a Bearer token in Angular 2 using a Web

I am currently working on asp.net web api and I am looking for a way to authenticate users using a bearer token. On my login page, I submit the user information and then call my communication service function: submitLogin():void{ this.user = this.l ...

Using TypeScript: How to access the "this" keyword within a method of an unidentified class

Within the code I'm working on, I am defining a new unnamed class that is implementing an interface. private service: CommandService; this.command = new class implements Command { execute(id: string): Promise<Result> { const resultId: st ...

A mistake has been identified: The object could potentially be 'null'. TS2531 for window.document

This is my first time integrating TypeScript into my project. When attempting to access something using window.document.getElementById(), I keep encountering the error: Type error: Object is possibly 'null'. TS2531 I've looked online for ...

Discover the origin file of a type with the TypeScript compiler API

Is there a way to determine the file where a specific type was defined given a ts.Program and the name of the type? The type will always exist in the program and be exported from the main entry point. I am looking for guidance on which APIs to use or an e ...

Converting JSON to objects in Angular 2 using Typescript

Being new to Angular2 and Typescript, I am currently in the learning phase. I am trying to retrieve data from a REST service and then populate a list with this data obtained from the service. The API link I am using is http://jsonplaceholder.typicode.com/u ...

Encountering the 'CreateVerificationTokenError' issue when trying to log in through EmailProvider using Prisma and Next-Auth

When working with next-auth and prisma adapter, I encountered an issue while trying to use the email provider. On my sign-in "Header," clicking it opens the /signin page without any problems. However, when attempting to sign in using the email provider, an ...

Utilizing refs in React to target a potentially null Typescript object

typescript is still showing an error An object may be 'null'.ts(2531) even after trying this code snippet myRef && myRef.current && myRef.current.focus(); when I attempt myRef?.current?.focus(); I encounter the following iss ...

Configuring relative file paths within the folders in tsconfig.json

In my project, I have set up a root folder named "TypescriptProgramming" which contains the tsconfig.json file. Inside this root folder, there is another folder called "chapter1" that further includes a folder named "minfunction". The minfunction folder ho ...

errorMessage": "Issue: Type Error - Unable to iterate over (intermediate value)

Currently, my setup involves using mysql2 to establish a connection with AWS Aurora DB. Unfortunately, I am encountering issues with connecting to the cluster and retrieving records. connection = createConnection({ host: 'music-instance-2 ...

Type with self-reference in index

Looking to create an interface with a mix of known and unknown members that should all have the same type. Here's what I have in mind: interface Foo { name?: string; [others: string]: Foo; } This setup would allow me to create something like ...

What is the best way to invoke a function in a class from a different class in Angular 6?

Below is the code snippet: import { Component, OnInit, ViewChild } from '@angular/core'; import { AuthService } from '../core/auth.service'; import { MatRadioButton, MatPaginator, MatSort, MatTableDataSource } from '@angular/mater ...