How to dynamically retrieve values from a const object literal using TypeScript

Currently, I am utilizing a TypeScript library known as ts-proto, which is responsible for generating TypeScript code.

The resulting generated code resembles the following:

//BasicMessage.ts

export interface BasicMessage {
  id: Long;
  name: string;
}

export const BasicMessage = {
 encode(message: BasicMessage) : Writer {
    ...
 }

 fromJSON(object: any): BasicMessage {
    ...
 }
}

as well as

// BasicMessagePlus.ts
  
 export interface BasicMessagePlus {
    id: Long;
    name: string;
    email: string;
 }

 export const BasicMessagePlus = {
   encode(message: BasicMessagePlus) : Writer {
      ...
   }

   fromJSON(object: any): BasicMessagePlus {
      ...
   }
 }

Due to the fact that this code is generated, modifications cannot be made. Therefore, my objective is to develop a method capable of encoding a type name and an object similar to the following example:

function encode(typeName: string, object: any): Writer {
  import(`/path/to/${typeName}`);
  return <typeName>.encode(<typeName>.fromJSON(object));
}

let writer1 = encode("BasicMessage", { id: 1, name: "Fake" });
let writer2 = encode("BasicMessagePlus", { id: 1, name: "Fake", email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4c2a2d27290c2a2d2729622f2321">[email protected]</a>" });

I have attempted various methods involving eval and globalThis without success in achieving the desired functionality. Any assistance would be greatly appreciated!

Answer №1

Working with dynamic imports can be a challenge for TypeScript to understand. What happens if the function is passed something like "ThisDoesNotExist"?

To address this, all items generated through dynamic imports should be imported into a single object for easy lookup:

import { BasicMessage } from './path/to/BasicMessage'
import { BasicMessagePlus } from './path/to/BasicMessagePlus'
const encodables = { BasicMessage, BasicMessagePlus }

By doing this, you can limit typeName to keys within that object for smooth operation:

function encode(
  typeName: keyof typeof encodables,
  data: any
): string {
  const encoder = encodables[typeName]
  return encoder.encode(encoder.fromJSON(data))
}

The third line of code may seem complex, but essentially it retrieves the type of the argument used in the encode method of the selected encoder.

Playground


It’s important to note that the data parameter here is of type any, reflecting the typing of your fromJSON method. If you need to enforce a specific type for the second argument based on the chosen encoder, the process becomes more intricate.

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

TypeScript error TS6053: Unable to locate file '.ts'

I encountered the following issue: Error TS6053: Could not find file 'xxx.ts'. Oddly enough, the file compiled without any issues yesterday. However, today it seems to be causing trouble. To troubleshoot, I ran a simple test: class HelloWorl ...

Why is it that I have intellisense enabled for .js files but not for .ts files?

Below is the content of my package.json: { "name": "edge-node-api", "version": "1.0.0", "description": "Web API for Edge Electrons customers", "main": "api.js", "scripts": { "test": "echo \"Error: no test specified\" &am ...

The promise object is displayed instead of the actual data retrieved from the API call

I am currently working on fetching data from an API and showcasing the name of the returned data on the front end. This function successfully retrieves the data through an API call: async function retrieveData(url){ var _data; let response = await fetch( ...

Error: The variable __WEBPACK_EXTERNAL_MODULE_XX__ has not been defined

A unique npm package called our-map has been developed utilizing TypeScript, webpack, and the ArcGIS JS API to encapsulate an esri map within a React component. The functionality of the module has been verified through testing on a dedicated page within th ...

Deploying AWS CDK in a CodePipeline and CodeBuild workflow

I am currently attempting to deploy an AWS CDK application on AWS CodePipeline using CodeBuild actions. While the build and deploy processes run smoothly locally (as expected), encountering an issue when running on CodeBuild where the cdk command fails w ...

Error thrown when attempting to pass additional argument through Thunk Middleware in Redux Toolkit using TypeScript

I have a question regarding customizing the Middleware provided by Redux Toolkit to include an extra argument. This additional argument is an instance of a Repository. During store configuration, I append this additional argument: export const store = con ...

Neglect variables that have not been declared (TypeScript)

Currently, I am working on developing a WebExtension using TypeScript that will be later compiled into JavaScript. This extension relies on one of the browser APIs offered by Firefox, specifically the extension API. An example of this is my use of the get ...

Encountering a NPM error when trying to launch the server using ng serve

I encountered an error : ERROR in /opt/NodeJS/FutureDMS/src/app/app.module.ts (5,9): Module '"/opt/NodeJS/FutureDMS/src/app/app.routing"' has no exported member 'APP_ROUTE'. Within my code, I have utilized arrow function in the loadCh ...

Is it possible for Typescript to allow extracted interfaces while excluding properties from another interface?

I've been searching for information on the specific features of this. Despite my efforts on Google, I have been unable to find the details. Any help would be greatly appreciated! interface Numbers { number: number; number2: number; number ...

Having Trouble with Imported JavaScript File in Astro

Why isn't the js file working in Astro when I try to import or add a source in the Astro file? For example: <script src="../scripts/local.js"></script> or <script>import '../scripts/local.js'</script> I am ...

The identifier 'id' is not recognized within the 'never' type in Angular

Hello there, I am currently working on a small project for a store website. You can find the project here. However, I have encountered an issue when trying to move items to the cart. Specifically, in the source code file app/components/product-list/produc ...

Having trouble setting a default value for your Angular dropdown? Looking for alternative solutions that actually work?

Objective: Customize the default value for a dropdown menu to switch between English (/en/) and Spanish (/es/) addresses on the website. Challenge: Despite extensive research, including consulting various sources like Angular 2 Dropdown Options Default Va ...

The process of modifying all interface values in typescript

Suppose I have a function that accepts a dynamic object as a parameter. const fun = <IValues>(values: IValues) => // IValues = {a: '', b: ''} My intention is to use that object and create a clone with the same keys but differ ...

What is the method for determining the type of a TypeScript class member that is associated with a commonly used symbol such as Symbol.toStringTag?

Does anyone know the correct TS syntax for extracting the type of a class method indexed with a well-known Symbol? Here are two incorrect methods: type T = String[Symbol.toStringTag]; // 'Symbol' only refers to a type, but is being used as a name ...

Typescript: Delay code execution until a function has completed running

I've encountered an issue with my code that involves calling a function. Here is the snippet of code in question: this.getAllOptions(questionID); console.log("++++++++++++++++++++++++++++++++"); console.log(this.result); The task of this function is ...

Find the variance between today's date and a selected date, then initiate the timer based on this variance

I have a grid containing data. I utilize the loadGrid() function to preload data or conditions before the grid finishes loading. When the active state is set to 1, my intention is to initiate a timer by calculating the difference between the current date ...

How to selectively make properties optional in Typescript conditions

Currently, I am working on creating a utility type to unwrap nested monads of Options in my code. Here is the progress I have made so far: export interface Option<T> { type: symbol; isSome(): boolean; isNone(): boolean; match<U>(fn: Mat ...

Stepper that is vertical combined with table information

I am currently facing a unique challenge with a component I'm trying to create. It's a combination of a vertical Stepper and a Datagrid. My goal is to group specific table sections within the content of a vertical Stepper, purely for data visual ...

Dealing with Axios errors and handling the response object from the err.response

My React/Redux action creator sends a post request when creating a new user account. During server validation testing, I expect the err.response object to be defined in the catch block and return the validation error message. However, I am seeing the gene ...

Having trouble connecting 'chartData' to a 'div' in Angular 2 because it is not recognized as a valid property?

While working on my Angular project, I encountered the following error that I have been unable to resolve: EXCEPTION: Uncaught (in promise): Error: Template parse errors: Can't bind to 'chartData' since it isn't a known property of ...