Determine the output type of a function in Typescript using an input value specified by an enum

I am currently saving settings to local storage and want to be able to input responses when retrieving (and possibly inserting) values from/to the storage.

After researching, it seems that using function overloading is the best approach. Here is what I have implemented so far:

export enum SettingsKey {
  hasOnboarded = 'hasOnboarded',
  phoneNumber = 'phoneNumber'
}

export async function getSetting(storage: Storage, key: SettingsKey.phoneNumber): Promise<string>
export async function getSetting(storage: Storage, key: SettingsKey.hasOnboarded): Promise<boolean>
export async function getSetting(storage: Storage, key: any) {
  return storage.get(key)
}

The issue I have with this solution is the possibility of forgetting to add a new element in the enum to the overload type definitions. Is there a way to ensure all enum values are accounted for? Or perhaps a better approach altogether?

Initially, I thought this would be a simple mapping from value hasOnboarded to return type boolean, but clearly it's more complex than that.

It seems like conditional types could potentially solve this problem, although I'm still trying to fully grasp how they work.

Another method I came across is described in this article, but it appears to involve additional complexity.

Any insights on this matter would be greatly welcomed!

Answer №1

To efficiently map between the enum and the promise return type, you can introduce an additional type. By adding a generic parameter to getSettings that extends the SettingsKey enum, we can utilize this generic type to access the mapping type. The specific enum member specified as an argument will help infer the generic parameter.

If any keys from the enum are missing in the mapping type, it will trigger an error within the function.

export enum SettingsKey {
    isLoggedIn = 'isLoggedIn',
    userName = 'userName'
}

type SettingsKeyType = {
    [SettingsKey.isLoggedIn]: boolean,
    [SettingsKey.userName]: string
}
export async function fetchSetting<K extends SettingsKey>(storage: Storage, key: K): Promise<SettingsKeyType[K]> {
    return storage.retrieve(key)
}
let x = fetchSetting(sessionStorage, SettingsKey.userName); // Promise<string>
let y = fetchSetting(sessionStorage, SettingsKey.isLoggedIn); // Promise<boolean>

// Similarly, a set function can be defined 
export async function updateSetting<K extends SettingsKey>(storage: Storage, key: K, value: SettingsKeyType[K]): Promise<void> {
   ///...
}

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 RadSideDrawer with Typescript in Vue class components: A Step-by-Step Guide

I am attempting to integrate external components into Vue Typescript Class Components. Following the installation of the standard template, I made modifications to its <script> block based on this guide: import { Vue, Component, Prop } from "vue-pro ...

unable to see the new component in the display

Within my app component class, I am attempting to integrate a new component. I have added the selector of this new component to the main class template. `import {CountryCapitalComponent} from "./app.country"; @Component({ selector: 'app-roo ...

Listen for incoming data from the client in the form of an ArrayBuffer

I have been utilizing the ws library within nodejs to develop a small cursor lobby where players can interact. I have managed to utilize the server to send ArrayBuffers with bit streams to the client and successfully decode them. However, I am encountering ...

Leverage the power of JavaScript functions within the app.component.ts file of

I have a JavaScript file named action.js and I am trying to incorporate it into an Angular project. After doing some research, I found out that the js file should be placed in the assets folder and the path must be referenced in the scripts array within an ...

Encountered an unexpected token error while using Jest with TypeScript, expecting a semicolon instead

I have been struggling to configure jest for use with typescript and despite trying several solutions, I am still facing issues. The error SyntaxError: Unexpected token, expected ";" keeps popping up, indicating that the configuration may not be compatible ...

I am facing a problem with the code for my React login page and router

My form page is built in react and typescript, utilizing JWT tokens on the API side. While there are no issues with the container page, I encountered an error on the index.tsx page where the routers are defined: A TypeScript error occurred in C:/Users/yusu ...

Node.js: Managing multiple occurrences of the same event name for testing purposes

When it comes to unit testing using mocha, I am looking for a way to set up an asynchronous queue for handling events. Previously, I used a once() Promise to wait for events like this: import EventEmitter from 'events' import { once } from ' ...

Instructions for adding a name to a string based on certain conditions

I am attempting to prepend a company name to a card number using the code provided. The challenge I am facing is incorporating the specific rules for each company as conditions for an if statement. Although I acknowledge that my current approach with the ...

Creating various subtypes for graphql-codegen

Currently, I am utilizing the typescript-operations package within the framework of the graphql-codegen library. Previously, I was accustomed to using Apollo's deprecated codegen and appreciated how it exported types seamlessly. For example, let&apos ...

What is the reason behind the checkbox event status returning the string "on" rather than true/false?

I have implemented a custom checkbox as a child component within a parent component. I properly pass the ngModel, name, etc., and attempt to update the model with a boolean status (true/false) based on the checkbox status using an EventEmitter. However, t ...

Develop a "Read More" button using Angular and JavaScript

I am in search of all tags with the class containtText. I want to retrieve those tags which have a value consisting of more than 300 characters and then use continue for the value. However, when I implement this code: <div class=" col-md-12 col-xl-12 c ...

Encountered an issue while attempting to authenticate CMS signature using pkijs

I am attempting to validate a CMS signature generated with open ssl using the following command: $ openssl cms -sign -signer domain.pem -inkey domain.key -binary -in README.md -outform der -out signature Below is my code utilizing pkijs: import * as pkij ...

Mastering the TypeScript syntax for executing the MongoDB find method

Having trouble properly typing the find method of MongoDB in my TypeScript project that involves MongoDB. Here's the snippet I'm working on: import { ReitsType } from '@/app/api/types/reits'; import { NextRequest, NextResponse } from &a ...

What is the best way to link this to a function in AngularIO's Observable::subscribe method?

Many examples use the Observable.subscribe() function in AngularIO. However, I have only seen anonymous functions being used like this: bar().subscribe(data => this.data = data, ...); When I try to use a function from the same class like this: update ...

Capturing page titles accurately for timeonsite tracker in a single-page Angular app is challenging when navigating to other pages

Implemented the timeonsite JS tracker in my Angular web application using HTML tags as shown below, <script type="text/javascript"> var Tos; (function(d, s, id, file) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementByI ...

Attempt to re-establish connection to server callback in Angular 2 upon encountering failure

tag, I have created an API parent class where all the necessary methods are implemented for server communication. The ApiService class is injected with Http and MdSnackBar services to handle HTTP requests and display snack bar messages. The get() method ...

Is it possible to create a single directive that can handle both Structural and Attribute behaviors?

Trying to develop an Angular Directive that will handle various functionalities based on config input values Dynamically add elements to the DOM based on input values (similar to ngIf) Apply styling to rendered elements Add attribute properties such as d ...

What factors does mongo consider when serializing an object?

I recently started working with BigNumbers from the bignumber.js package As I delve into Mongo, I find myself pondering how Mongo manages to serialize objects correctly, such as the BigNumbers. In my case, I have encountered a puzzling situation where two ...

What is the best way to create an Office Script autofill feature that automatically fills to the last row in Excel?

Having trouble setting up an Excel script to autofill a column only down to the final row of data, without extending further. Each table I use this script on has a different number of rows, so hardcoding the row range is not helpful. Is there a way to make ...

Developing an asynchronous function to retrieve data from an external API utilizing Await/Async strategy

Currently, there is a method under development that retrieves a value from the API. What steps are needed to properly integrate Async/Await functionality into this process? fetchAccountById(){ let accountName; this.accountService.fetchDa ...