A Typescript function will only return a partial if the parameter passed into it is also

I have a function that takes a camelCase object and returns the same object in snake_case format.

// Let's consider these types
interface CamelData {
   exempleId: number
   myData:string
}

interface SnakeData {
   exemple_id: number
   my_data: string
}

export const camelToSnake = (
  camelData: Partial<CamelData>
): Partial<SnakeData> => {
  return {
    exemple_id: camelData.exempleId,
    my_data: camelData.myData
}

My goal is to make sure that the return type of the function is SnakeData when the input type is CamelData.

I'm looking for a solution that works like this:

export const camelToSnake = (
  camelData: Partial<CamelData>
): if (camelData is of type CamelData) {SnakeData} else {Partial<SnakeData>} => {
  return {
    exemple_id: camelData.exempleId,
    my_data: camelData.myData
}

Any suggestions or help would be greatly appreciated. Have a wonderful day!

Answer №1

Understanding Function Overloading:

export function convertCamelToSnake (camelData: CamelData): SnakeData;
export function convertCamelToSnake (camelData: Partial<CamelData>): Partial<SnakeData>;
export function convertCamelToSnake (camelData: Partial<CamelData>): Partial<SnakeData> {
  return {
    example_id: camelData.exampleId,
    my_data: camelData.myData
  }
}

Answer №2

To handle conversions between CamelCase and snake_case, you can utilize a generic type for the input where if it extends CamelData, the return type will be SnakeData. Otherwise, partials can be used:

// Let's consider these interface types
interface CamelData {
   exempleId: number
   myData: string
}

interface SnakeData {
   example_id: number
   my_data: string
}
// Specifying the exported call signature separately helps to simplify typechecking inside the function
// Using one call signature is possible, but convincing TypeScript that the data fits the type `T extends CamelData ? SnakeData : Partial<SnakeData>` without typecasts is challenging.
export function camelToSnake<T extends Partial<CamelData>>(
  camelData: T
): T extends CamelData ? SnakeData : Partial<SnakeData>
export function camelToSnake(
  camelData: Partial<CamelData>
): Partial<SnakeData>{
  return {
    exemple_id: camelData.exempleId,
    my_data: camelData.myData
    }
}

const x = camelToSnake({exempleId:1})
//   ^? const x: Partial<SnakeData>
const y = camelToSnake({exempleId:2, myData: "hi"})
//   ^? const y: SnakeData

playground link

For simplicity in typechecking, I have utilized a single overload to avoid complex checks within the function for conditional types. If needed with arrow notation, it would be the only viable option:

const camelToSnake = <T extends Partial<CamelData>>(
    camelData: T
):T extends CamelData ? SnakeData : Partial<SnakeData> => ({
    exemple_id: camelData.exempleId,
    my_data: camelData.myData
} as T extends CamelData ? SnakeData : Partial<SnakeData>)

Answer №3

Just thought I'd share the solution I ended up going with for my question. Big thanks to everyone who provided helpful comments and answers that led me to this decision.

interface CamelData {
   exempleId: number
   myData:string
}

interface SnakeData {
   exemple_id: number
   my_data: string
}

type SnakeDataFor<T extends Partial<CamelData>> = {
    example_id: T['exampleId'];
    my_data: T['myData'];
}

export function camelToSnake(camelData: CamelData): SnakeData;
export function camelToSnake<T extends Partial<CamelData>>(
  camelData: T
): SnakeDataFor<typeof camelData>;
export function camelToSnake<T extends Partial<CamelData>>(
  camelData: T
): SnakeDataFor<typeof camelData> {
  return {
    exemple_id: camelData.exempleId,
    my_data: camelData.myData
  }
}

This solution is a bit more advanced than what I initially requested. It returns SnakeData if the parameter is of type CamelData, otherwise it returns a custom type with the same properties as the parameter.

I'll update this post if I come across a better solution in the future.

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

Craft a unique typings file tailored to your needs

After recently creating my first published npm package named "Foo", I encountered some difficulties while trying to consume it in a TypeScript project. The tutorials on how to declare modules with custom typings were not clear enough for me. Here are the k ...

What causes the "This page isn't responding" error to pop up in Edge and Chrome browsers while attempting to perform consecutive tasks in a web application built with Angular 8?

Trouble with Page Loading Whenever this error occurs, I find myself unable to perform any activities on that page. The only solution is to close the tab and open a new one. My current code allows me to navigate through an array list (Next and Previous) us ...

Tips for optimizing the performance of nested for loops

I wrote a for loop that iterates over 2 enums, sending them both to the server, receiving a value in return, and then calculating another value using a nested for loop. I believe there is room for improvement in this code snippet: const paths = []; for awa ...

The array remains undefined even after being assigned within the subscribe function

I have encountered an issue in my Angular app where the array productLocations is being assigned in the ngOnInit method within a subscription, but it remains undefined when used in another method. Despite following advice on Stackoverflow to move the assig ...

JavaScript/Typescript is throwing an error because it is unable to access the property 'username' of an undefined object

In my project, I am attempting to compile a list of Profile objects and then extract specific elements from each object in the list. To accomplish this, I have defined a public interface named Profile, imported it into my component, and instantiated a new ...

Tips for showing nested array values in Angular 8

I'm new to using angular and I'm attempting to display values from an array within another array in a table format. Here is my JSON array that I'd like to display in rows: { "data": { "Influencer": [ { ...

What is the reason for the retrieval of jquery-3.5.1.min.js through the request.params.id expression?

For my school project, I am using Express.js with TypeScript to create a simple app. This router is used for the edit page of a contact list we are developing. It displays the ID of the current contact being edited in the search bar. The problem arises whe ...

Guide on Executing a Callback Function Once an Asynchronous For Loop Completes

Is there a way to trigger a callback function in the scan function after the for await loop completes? let personObj = {}; let personArray = []; async function scan() { for await (const person of mapper.scan({valueConstructor: Person})) { ...

Guide on creating a static method to generate a subclass instance

I am currently working on creating an abstract class called Enum, which consists of static methods that return instances of the class they are invoked upon. However, I am encountering difficulties in properly typing these methods. My goal is to help TypeS ...

Sidenav Angular Material cdkScrollable is an effective tool for creating scrollable

In Angular Material CDK, there is a special Directive called CdkScrollable that allows you to monitor ScrollEvents within a specific container. I am currently attempting to retrieve the CdkScrollable associated with the default MatSidenavContent. Unfor ...

Access basePath within the Next.js AppRouter

Is there a way to access the basePath in Next.js 13 when using AppRouter? To retrieve it, we can simply get router.basePath through the useRouter hook of PageRouter by importing `import { useRouter } from 'next/router' I am currently unable to ...

acquiring the main class instance within a function without relying on an arrow function

Within my Angular project, I have integrated a datatable with row grouping and row callbacks. Datatable Options openPositionDatatableOptions = { sDom: 'rt<"bottom"p>', ajax: (data, callback, settings) => { this.service.ge ...

Set up a TypeScript project with essential dependencies for creating multiple raw JavaScript output files

Currently, I am in the process of developing scripts for Bot Land, a real-time strategy game that offers a unique gameplay experience. Rather than controlling units traditionally with a mouse and keyboard, players code their bots using an API to engage in ...

Definition of TypeScript array properties

Having some trouble creating a type for an array with properties. Can't seem to figure out how to add typings to it, wondering if it's even possible. // Scale of font weights const fontWeights: FontWeights = [300, 400, 500]; // Font weight alia ...

Determining the function return type by analyzing an array of functions

If you have a vanilla JavaScript function that accepts an array of callbacks (each returning an object) and combines their outputs, how can TypeScript be used to determine the return type of this function? While ReturnType is typically used for a single ...

Angular2 Cache: Enhance Your Application's Performance

Currently seeking a cache solution for my Angular2 application. Imagine we have a massive collection of Movie objects stored on a server, too many to fetch all at once. The server offers a REST endpoint: getMovie(String id) On the client side, I need a s ...

Trouble encountered with Angular Google Maps integration when using router-outlet

Currently, I am in the process of developing an application that features a map as its header (providing a global view) and another map positioned in the center of the page to showcase detailed views. To demonstrate this setup, I have shared a working exam ...

Tips on resolving handlebars 'module not found' error in typescript while compiling to umd

In my client-side JavaScript library written in TypeScript, I am attempting to incorporate Handlebars. However, when I try to import using import * as Handlebars from 'handlebars', I encounter an error message stating that TypeScript "cannot find ...

What steps can I take to ensure that the upper and left sections of a modal dialog remain accessible even when the size is reduced to the point of overflow?

One issue I'm facing is with a fixed-size modal dialog where part of the content gets cut off and becomes inaccessible when the window shrinks to cause an overflow. More specifically, when the window is narrowed horizontally, the left side is cut off ...

Setting up ESLint for TypeScript with JSX configuration

I am encountering problems with TypeScript configuration. Below is the code snippet from my tsconfig.json: { "compilerOptions": { "target": "es5", "lib": [ "dom", "dom.iterable", "esnext" ], "allowJs": true, "skipLib ...