Converting unknown attributes into choices that can be omitted

I am currently working on creating a mapped type that will turn certain properties into optional ones if they can be undefined.

To elaborate, my starting point is a type structured like this:

interface Input {
  foo: string;
  bar: string | undefined;
  baz: number | undefined;
}

The objective is to use a Mapped Type to convert it into the desired structure below:

interface Output {
  foo: string;
  bar?: string;
  baz?: number;
}

All the examples I have come across so far demonstrate making all properties optional, but that's not exactly what I need in this case.

Answer №1

Below is a potential solution (utilizing TS 4.1):

interface Input {
    foo: string;
    bar: string | undefined;
    baz: number | undefined;
}

type UndefinedToOptional = { 
  [K in keyof Input as undefined extends Input[K] ? K : never]?: Input[K] 
}

type T1 = Omit<Input, keyof UndefinedToOptional> & UndefinedToOptional
/* 
{
    foo: string;
    bar?: string | undefined;
    baz?: number | undefined;
}
 */

Answer №2

interface InputData {
  name: string;
  type: string | undefined;
  value: number | undefined;
}

// test cases
const data1: InputData = { name: '' } // error
const data2: InputData = { name: '', type: '', value: undefined } // valid

type UndefinedProperties<T> = {
  [P in keyof T]: undefined extends T[P] ? P : never
}[keyof T];

type RemoveUndefinedValues<T> = {
  [P in keyof T]: undefined extends T[P] ? NonNullable<T[P]> : never;
}

type OutputData = 
  Omit<InputData, UndefinedProperties<InputData>> // { name: string }
  & Partial<RemoveUndefinedValues<Pick<InputData, UndefinedProperties<InputData>>>; // { type: string; value: string; }

// test cases for output
const result1: OutputData = { name: '' }; // valid
const result2: OutputData = { name: '', type: '', value: undefined } // valid

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

Enhance your PowerBI dashboards with the ChatGPT Custom Visual!

I am currently working on developing a custom visual for Power BI using TypeScript. This visual includes an input field for user prompts and another input field for ChatGPT answers. The main goal is to allow users to ask questions about the data in their r ...

Retrieve all work items from Azure DevOps by utilizing the GET API endpoint

I am currently working with TypeScript and using a GET API to display all work items in the UI. At the moment, there are 4 work items visible on the UI. Along with this, I am also utilizing a POST API to add new work items so that they can be reflected bot ...

The addition operator is not compatible with the given types

Hello, I am currently working on integrating PayPal into an Angular 5 project. The code snippet below shows how I render PayPal buttons using a function: ngAfterViewChecked(): void { if (!this.addScript) { this.addPaypalScript().then(() => { ...

Organizing a mat-table by date does not properly arrange the rows

My API retrieves a list of records for me. I would like to display these records sorted by date, with the latest record appearing at the top. However, the TypeScript code I have written does not seem to be ordering my rows correctly. Can anyone assist me ...

Tips on mocking a function using Jest

I'm currently working on testing a typescript class using Jest. Here is the class I am trying to test: //MyClass.ts import { foo } from './somewhere/FooFactory'; export class MyClass { private _state : number; constructor( arg : string ...

What is the reason behind TypeScript's decision not to raise an error in case of a mismatched function argument type?

Here's a simple illustration to showcase my point: type Info = { id: number; } type ImportantInfo = { id: number; value: 5; } type Task = (data: Info) => void; const task: Task = data => null; const data: ImportantInfo = { i ...

Creating Dynamic Graphs using Angular and Chart.js with Array Values

I have implemented ChartJS-2 to visualize a graph displaying an array of user activities, but it appears distorted: import { Component, OnInit, Input } from '@angular/core'; import { ChartOptions, ChartType, ChartDataSets } from 'chart.js ...

The `sonarqube-scanner@^4.0.0` does not produce a non-zero exit code when a Quality Gate failure occurs

Latest SonarQube: Developer Edition v10.5.1 (90531) Sonarqube-scanner version: 4.0.0 or 4.0.1 Utilized npm package: https://www.npmjs.com/package/sonarqube-scanner Node.js version: 20.14 Upon executing the following command: npx sonarqube-scanner@^4.0.0 - ...

There is no equality between two required types that are equivalent

When trying to assign Required<T> (where T extends A) to Required<A>, the operation fails. Consider this simplified example: type A = { a?: number }; type B<T extends Required<A>> = T; type C<T extends A> { b: B<Requir ...

Retrieving the chosen option from a dropdown menu using AngularJS

<tr (click)="onRowClick(myDropDownList.value)"> <td> <select #myDropDownList (click)="$event.stopPropagation()" (change)="onChange($event.target.value)"> <option *ngFor="let n of numbers" [value]="n">{{n}}</option> </se ...

Adding date restrictions to the main method is necessary for controlling the input and output

I have a function in my react-native package that requires "from" and "to" dates as parameters. I need to implement a rule that ensures the "to" date is always after the "from" date. Where should I insert this requirement in the following code snippe ...

Can functions be stored and invoked within a dictionary in TypeScript?

Currently, I'm in the process of refactoring some code and had a question regarding the possibility of declaring and initializing a dictionary that contains factory functions, with each function being associated with an enumerator key. This setup woul ...

How can we import the entire Jasmine library using CucumberJS?

I am currently trying to implement unit testing using Jasmine and CucumberJS in my Angular v9 application. I have followed the tutorial provided by cucumber.io to set up cucumber as the default runner. However, I am facing difficulties in using Jasmine met ...

The function within filereader.onload is not running properly in JavaScript

When working with FileReader to read a file and convert it to base64 for further actions, I encountered an issue. Although I was able to successfully read the file and obtain its base64 representation, I faced difficulties in utilizing this data to trigger ...

Creating a Vue 3 Typescript project may lead to encountering the error message "this is undefined"

Just diving into Vue using Vite and TypeScript for my project, but running into errors during the build process. Most of them are Object is possibly 'undefined', particularly in parts of my template like this: <input :value="this.$store.s ...

Improving the method of retrieving RTK result within getServerSideProps

Currently, I am utilizing RTK Query to make an API call within my getServerSideProps function. While I can successfully retrieve the result using the code snippet provided below, I find the process somewhat awkward. Additionally, the result lacks proper ty ...

Error: "Cannot find module 'tsc' in TypeScript, Express, and React application during deployment on Heroku

Currently, I am working on developing an Express app using TypeScript and a React app bootstrapped with create-react-app in JavaScript. The project has a specific directory structure which can be viewed here. The server code is located within the server/sr ...

Switch up row values in an array and transform them into an object using SheetJS

I am struggling to format an array where each "Working Day" is represented as an object with specific details like index and start/end date. I need help manipulating the JSON data to achieve the desired structure. The package I'm currently using is: ...

What is the best way to provide data types for Vuex mapState functions?

In my Vuex component using Typescript, I want to add types to the mapping functions in mapState. Previously, I had it set up like this: @Component({ computed: { ...mapState( MY_NAMESPACE, { fooIndex: ( state: MyModel ) => state.values.index ...

What sets apart Records and Objects in TypeScript?

I am exploring how to define a conditional type in TypeScript that can differentiate between "record" types (with dynamic/unbounded keys) and plain object types (with predefined keys). type R = { [x: string]: any } type O = { a: string; b: number } One ap ...