What is the process of generating a new type in TypeScript based on another type with a distinct property of a different type?

I am defining a type as follows:

type Period = 'Monthly' | 'Yearly'
type Cycle = {
    period: Period,
    price: number
}

Now, I am looking to modify this type so that the 'period' property can also accept an empty string:

type Period = 'Monthly' | 'Yearly'
type EditableCycle = {
    period: Period | '',
    price: number
}

My initial idea was to use this hypothetical syntax:

type EditableCycle = Extend<Cycle, { period: '' }>

Can anyone provide guidance on how to implement this change?

The rationale behind this modification is to allow users to leave the 'period' field empty during editing, while ensuring that a valid Period will be assigned after validation.

Please note that the actual type structure is more intricate than Cycle, involving arrays and other complex elements. This is just a simplified example.

Answer №1

One way to modify the period field is by using the Omit utility type:

type Period = 'Monthly' | 'Yearly'
type Cycle = {
    period: Period,
    price: number
}

type EditableCycle = Omit<Cycle, "period"> & {
  period: Period | ''
}

const editableCycle: EditableCycle = {
  period: '',
  price: 5
}

If you want to take it a step further, consider creating your own Override type:

type Period = 'Monthly' | 'Yearly'
type Cycle = {
    period: Period,
    price: number
}

type Override<T, K> = Omit<T, keyof K> & K

type EditableCycle = Override<Cycle, {
  period: Period | ''
}>

const editableCycle: EditableCycle = {
  period: '',
  price: 5
}

I trust this information proves to be beneficial to you.

Regards, François

Answer №2

Would you consider defining it like this instead:

const PeriodType = 'Monthly' | 'Yearly'
const CycleType = {
    period: PeriodType,
    price: number
}

const EditableType<T> =  {
  [Key in keyof T]: T[Key] extends string? (T[Key] | '') : T[Key];
};

const EditableCycleType = EditableType<CycleType>; // -->  period: "" | PeriodType;

Answer №3

Learn how to utilize the Extend tool in your code (I've rebranded it as UnifyProps to merge properties from two parameters, creating a unified type with shared names):

TS Playground link

type UnifyProps<T1, T2> = {
  [K in keyof T1]: K extends keyof T2 ? (T1[K] | T2[K]) : T1[K];
} & {
  [K in keyof T2]: K extends keyof T1 ? (T1[K] | T2[K]) : T2[K];
};

type Period = 'Monthly' | 'Yearly';

type Cycle = {
  period: Period;
  price: number;
};

type EditableCycle = UnifyProps<Cycle, { period: '' }>;

declare const ec: EditableCycle;
ec.period = 'Monthly'; // ok
ec.period = 'Yearly'; // ok
ec.period = ''; // ok
ec.period = 'another string'; /*
^^^^^^^^^
Type '"another string"' is not assignable to type '"" | Period'. (2322) */

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

Using TypeScript import statements instead of the <reference path...> in an ASP.NET Core web application: A step-by-step guide

Understanding the Setup I initially had a functional TypeScript Hello World in my ASP.NET Core Web application. To compile TypeScript, I used the NuGet package "Microsoft.TypeScript.MSBuild" Version="4.4.2" along with a tsconfig.json f ...

"Perform an upsert operation with TypeORM to create a new entry if it

Is there a built-in feature in TypeORM to handle this scenario efficiently? let contraption = await thingRepository.findOne({ name : "Contraption" }); if(!contraption) // Create if not exist { let newThing = new Thing(); newThing.name = "Contrapt ...

Coverage of code in Angular2 using Qunit

Is there a reliable code coverage measurement tool or framework that can easily be integrated to assess the code coverage of Angular2-TypeScript code with QUnit tests? I have come across some frameworks like remap-istanbul, blanket.js etc., but these fram ...

Guide on obtaining Elastic search documents in the specified order of identifiers

Given a specific order of document IDs [1, 4, 2, 5] and some filtering criteria { match: {...} }, what is the most efficient method to ensure that the resulting documents are retrieved in the desired order [1, 4, 2, 5]? Here is an example of a sample docu ...

Creating objects based on interfaces

After looking at this straightforward code: interface int1 { aa: string, bb: number, } const obj1:int1 = {} //#1 function fun(param_obj:int1) { //#2 } I am curious as to why the compiler throws an error: Type '{}' is missing the fol ...

Error: UserService (?) is missing parameters and cannot be resolved

Upon compiling my application, an error is appearing in the console: Uncaught Error: Can't resolve all parameters for UserService (?) Despite having @Injectable() present for the UserService, I am unsure where to troubleshoot further. import {Inj ...

Tips for writing an async function using TypeScript

I've been working with Typescript and NLP.js. However, I'm encountering an issue where the argument manager is displaying 'Parameter manager implicitly has an any type'. I attempted to use :, but it didn't solve the problem eff ...

Separate an array in TypeScript based on the sign of each number, and then replace the empty spaces with null objects

Hey, I'm facing a little issue, I have an Array of objects and my goal is to split them based on the sign of numbers. The objects should then be dynamically stored in different Arrays while retaining their index and getting padded with zeros at the b ...

Creating a constant.ts file to define universal constantsWould you like assistance with anything else

Is there a way to create a constant.ts file or use a command to declare all global constants and export them for easy access? ...

The production build encountered an issue as it was anticipating 3 arguments, however, it only received

import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'elipsis' }) export class ElipsisPipe implements PipeTransform { transform(text, length, clamp) { text = text || ''; clamp = clamp || '...& ...

"Ionic 3: Utilizing the If Statement within the subscribe() Function for Increased Results

I added an if conditional in my subscribe() function where I used return; to break if it meets the condition. However, instead of breaking the entire big function, it only breaks the subscribe() function and continues to execute the navCtrl.push line. How ...

Guide on utilizing the h function in Vue3 for seamless binding and passing of properties and events from parent to child components

Utilizing Vue3 and naive ui for front-end development has been a challenge for me as I primarily focus on back-end development and lack expertise in front-end technologies. To enhance user interaction, I incorporated naive ui’s BasicTable along with an ...

Is it possible that a declaration file for module 'material-ui/styles/MuiThemeProvider' is missing?

I have been trying to implement the react material-ui theme after installing it via npm. However, I am encountering errors when adding 'import MuiThemeProvider from "material-ui/styles/MuiThemeProvider";' in boot-client.tsx: TS7016: Could not ...

What is the best way to clear a token from SessionStorage upon exiting an Angular application?

I need to clear my sessionStorage every time I exit my application. App Module: export class AppModule implements OnInit, OnDestroy{ constructor(private overlayService: OverlayService, private logger: LoggerService, private userService: UserService, pr ...

Ways to establish the relationship between two fields within an object

These are the definitions for two basic types: type AudioData = { rate: number; codec: string; duration: number; }; type VideoData = { width: number; height: number; codec: string; duration: number; }; Next, I need to create a MediaInfo typ ...

Validating nested objects in YUP with the potential for zero or multiple properties present

I am currently working on setting up yup validation for this object: placements: { 3: {}, 5: {}, 6: {0: 'D17'}, 7: {}, 8: {}, 9: {}, 10: {}, 11: {}, } The challenge I am facing is that an entry like 3: {} can be empty, and that's totally fi ...

Using Typescript to define the type for React's useState() setter function whenever

I'm working on setting up a React Context to handle parameters mode and setMode, which act as getter and setter for a React state. This is necessary in order to update the CSS mode (light / dark) from child components. I'm encountering a Typescr ...

Testing vue-router's useRoute() function in Jest tests on Vue 3

Struggling with creating unit tests using Jest for Vue 3 components that utilize useRoute()? Take a look at the code snippet below: <template> <div :class="{ 'grey-background': !isHomeView }" /> </template> &l ...

You cannot assign type 'Node | null' to type 'Node' when attempting to loop through HTML elements in TypeScript

In my code, I am taking a raw Markdown string stored in 'markdownString' and using the marked.js library to convert it to HTML for display on a web browser. My goal is to extract all plain text values from the page and store them in an array of s ...

It is possible that the object may be null, as indicated by TS2531 error

I was interested in using QrReader to scan a file based on [https://github.com/Musawirkhann/react_qrcode_generation_scanner This code is written in react, but I wanted to use it with tsx. However, when attempting to implement it, I encountered an error: ...