Using the Typescript Compiler API to extract the exported typescript object

Currently, I am exploring the functionality of the Typescript Compiler API along with the local file system to access the exported object from a typescript config file and integrate it into node.js.

Consider the following simple example:

// sample.config.ts

type Config = {
  hello: string;
};

const config: Config = {
  hello: "world",
};

export default config;

In a separate file, how can I utilize the Compiler API to extract the exported object and assign it to a variable for use in js?

//another-file.js

const source = "./sample.config.ts"

let exportedObject = /* code using Compiler API function(s) to fetch exported object from 'sample.config.ts' */

console.log(exportedObject.hello)
// outputs "world"

I have managed to load a program and source file, but I need guidance on what steps to take next. Any recommended documentation or resources are highly appreciated!

//another-file.js
const source = "./sample.config.ts";

const program = ts.createProgram([source]);
const sourceFile = program.getSourceFile(source);

Answer №1

If you're looking to access the module exports, you can utilize the TypeChecker#getExportsOfModule method:

const checker = program.getTypeChecker();

const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile)!;
const exports = checker.getExportsOfModule(sourceFileSymbol);

From there, you can check for a default export within the exports list, represented as a ts.Symbol:

const defaultExportSymbol = exports.find(e => e.escapedName === "default")!;

By accessing the type of the default export, you can then investigate its properties:

const defaultExportType = checker.getTypeOfSymbolAtLocation(
  defaultExportSymbol,
  defaultExportSymbol.declarations![0],
);

for (const prop of defaultExportType.getProperties()) {
  const propType = checker.getTypeOfSymbolAtLocation(prop, prop.declarations![0]);
  console.log(prop.name); // hello
  console.log(checker.typeToString(propType)); // string
}

If any issues arise, consider checking

console.log(ts.getPreEmitDiagnostics(program))
to ensure there are no errors in the program.

Retrieving config

To obtain the config, you'll need to retrieve the alias symbol of the default export:

const configSymbol = checker.getAliasedSymbol(defaultExport);

With this symbol, you can access the variable declaration and the object literal expression of the initializer to extract the values:

const configDecl = configSymbol.declarations![0] as ts.VariableDeclaration;
const objLit = configDecl.initializer as ts.ObjectLiteralExpression;

for (const prop of objLit.properties) {
  console.log(prop.name!.getText()); // hello
  console.log((prop as ts.PropertyAssignment).initializer.getText()); // "world"
}

While this code includes many assertions, it's important to write code that is adaptable and handles various scenarios effectively.

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

Invoking a function on an immutable object

I have a code snippet that looks like this: private get headers(): Headers { const headers = new Headers(); headers.set('Authorization', `Bearer ${this.auth.tokenSnapshot}`); return headers; } The variable headers is defined as ...

What could be the reason why the getParentWhileKind method in ts-morph is not returning the anticipated parent of the

Utilizing ts-morph for code analysis, I am attempting to retrieve the parent CallExpression from a specific Identifier location. Despite using .getParentWhileKind(SyntaxKind.CallExpression), the function is returning a null value. Why is this happening? I ...

Assign a default value to empty elements in an array

Here is an example of fetching data in an array: [ { "Id": 111, "Name": "Test 1", "Email": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8de8e0ece4e1bccde9e2e0ece4e3a3e3e8f9">[email protect ...

You haven't included an index signature in the TypeScript type

I am creating MyInterface.dic to function as a dictionary with the format name: value, and here is how it is defined: interface MyInterface { dic: { [name: string]: number } } Next, I am writing a function that expects my specific type: function foo(a ...

Tips for using Cookie Service in Angular 2

I am struggling to remove a specific cookie from my system and I don't have access to the necessary package that can help me resolve this issue. ...

Toggle visibility between 2 distinct Angular components

In my application, I have a Parent component that contains two different child components: inquiryForm and inquiryResponse. In certain situations, I need to toggle the visibility of these components based on specific conditions: If a user clicks the subm ...

Creating a Typescript empty object to manage state in a React component

I'm currently working on creating a type for a specific object that has the possibility of being empty. Let's start by defining the state for our React class, beginning with the CharacterInventoryTabsState interface: export default interface Char ...

Facing challenges with incorporating Prisma Schema into a PNPM monorepo alongside NestJS due to ESM complications

I've set up a PNPM monorepo containing two identical NestJS apps (apps/api and apps/backend) and one Prisma database package (packages/database). When trying to run the api using start:dev, I encountered the following error message: (node:69498) Warni ...

Node.js E2E test for endpoint involving an asynchronous operation that is not being properly handled

Currently, I am working on developing an API in Node.js using NestJS. One of the endpoints within this API calls two asynchronous services. The first service is awaited and its result is then returned in the response. However, the second service is allowed ...

Leveraging ngIf and ngFor within choice

Is there a way to combine ngIf and ngFor in a single line of code? Here is the code snippet I am currently using: <option *ngIf="tmpLanguage.id!=languages.id" *ngFor="let tmpLanguage of languages" [ngValue]="tmpLanguage.id"> {{tmpLang ...

Utilizing interface in NestJS for validating incoming request parameters

My goal is to utilize the interface provided by class-validator in order to validate a specific field in the incoming request body. Here's the interface structure: export enum Fields { Full_Stack_Dev = 'full stack dev', Frontend_Dev = &a ...

Execute a function when a button is pressed in a React application

Currently, I am dynamically generating some HTML and have a requirement for certain "events" to trigger an onclick function. The technology stack I am using for this project involves React and TypeScript. My initial approach is as follows: function add_ev ...

Tips for crafting a test scenario for input alterations within Angular

Hello there, currently I am working on an application using Angular and TypeScript. Here is a snippet of my template code: <input type="text" placeholder="Search Results" (input)="searchInput($event)"> And here is the TypeScript code for the searc ...

"What is the significance of the .default property in scss modules when used with typescript

When dealing with scss modules in a TypeScript environment, my modules are saved within a property named default. Button-styles.scss .button { background-color: black; } index.tsx import * as React from 'react'; import * as styles from ' ...

What is the process for creating a method within a class?

Here is the current structure of my class: export class Patient { constructor(public id: number, public name: string, public location: string, public bedId: number, public severity: string, public trajectory: number, public vitalSigns: ...

Comprehending Angular 5's Importing External Classes

I have developed a class structure for managing Schedules. I then brought in this class to my primary program. My issue arises from the fact that this class utilizes the HttpClient, which I was instructed to set up within the constructor. As a result, when ...

What is the best way to organize the data retrieved from the api into a map?

In my search page component, I display the search results based on the user's query input. Here is the code snippet: "use client"; import { useSearchParams } from "next/navigation"; import useFetch from "../hooks/useFetch&qu ...

Tips for resolving TS7022 issue within Vue Composition API

I encountered an issue while attempting to import a component in my file that generated the following error message: TS7022: 'default' implicitly has type 'any' because it does not have a type annotation and is referenced directly or in ...

Whenever a call to `http.put` is made, it is certain that

I am facing an issue with my form in Angular 2. When the user clicks on the submit button, I intend to send the data to a rest endpoint using the http module. Here is the structure of the form: <form novalidate [formGroup]="formGroup()" (ngSubmit)="sen ...

Is it possible to make *ngIf in Angular run just one time?

I am facing a minor issue - I need to implement roles validation in my Angular application. The structure of the application consists of pages, each containing multiple components. User privileges are assigned at the component level, making it necessary to ...