Ensuring javascript files are cognizant of their corresponding typescript definition files

You can utilize Typescript to create .d.ts definition files for your local javascript files. Consider the following file structure:

src/
  main.js
  imported.js
  imported.d.ts

main.js

import { func } from './imported';
console.log(func("1", "1"));

imported.js

export const func = (numVal, strVal) =>
  `The number is ${numVal}, the string is ${strVal}`;

imported.d.ts

export const func: (numVal: number, strVal: string) => string;

When using the noImplicitAny option, you may encounter errors like:

src/imported.js(1,22): error TS7006: Parameter 'numVal' implicitly has an 'any' type.
src/imported.js(1,30): error TS7006: Parameter 'strVal' implicitly has an 'any' type.
src/main.js(3,18): error TS2345: Argument of type '"1"' is not assignable to parameter of type 'number'.

The last error ensures type safety by preventing passing a string instead of a number as required. However, in the imported javascript file, the parameters' types are not recognized, hindering the use of noImplicitAny and potentially leading to errors when passing incorrect types.

Is there a way to enable javascript files to acknowledge their definitions in Typescript without altering the original javascript code?

Answer №1

While JavaScript files cannot automatically recognize their definition files, Typescript 2.3 introduced a feature to enable type checking using JSDoc comments.

Consider the following project structure:

src/
  main.js
  imported.js

imported.js

/**
 * @return {string} 
 * @param {number} numVal 
 * @param {string} strVal 
 */
export const func = (numVal, strVal) =>
  `The number is ${funcs.func3(numVal)}, the string is ${strVal}`;

main.js

import { func } from './imported';

/**
 * Works fine
 * @param {number} number 
 */
const mainFunc1 = (number) =>
  func(number, "Hello");      

/**
 * Argument of type 'string' is not assignable to parameter of type 'number'
 * @param {string} string 
 */
const mainFunc2 = (string) =>
  func(string, "Hello");

The TypeScript compiler now recognizes that numVal is a number and strVal is a string, preventing errors when passing incorrect types to functions. The @return in func may be redundant, but it promotes consistency in code documentation.

Although modifying original JavaScript code is necessary, only comments are used for type checking.

Limitations

While this approach doesn't provide all features of full TypeScript type checking, it covers most scenarios. For instance, when a module returns an object with typed keys:

/**
 * @param {number} num 
 */
const func1 = (num) => num * 2;

export default {
  func1,
}

When consuming this module:

import imported from './module';

imported.func1(3);    // No error
imported.func1("3");  // Error
imported.func2(3);    // No error, should be flagged

In JavaScript files, missing types for default exports can lead to undetected issues like calling undefined properties. In contrast, TypeScript would accurately point out such problems without explicit type declarations.

Typescript 2.5

Version 2.5 also introduced support for type assertion using JSDoc comments, as shown here:

// Argument of type 'string | number' is not assignable to parameter of type 'number'.
const func1 = () =>
  func(funcReturnsNumberOrString(true), "Hi");

// Fine
const func2 = () =>
  func(/** @type {number} */ (funcReturnsNumberOrString(true)), "Hi");

/**
 * @returns { number | string }
 * @param {boolean} bool
 */
const funcReturnsNumberOrString = (bool) =>
  bool ? 2 : "2";

In this case, by applying JSDoc annotations correctly, TypeScript can infer and enforce types more 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

Javascript SVG object reference

I am facing an issue. I created a sketch using another program and saved it as an svg file. Now, I want to display this file on a website. I have created a div with an id and used JavaScript to load the svg file into that div. However, when trying to a ...

Retrieve the header tag from API using Nuxt

I am trying to dynamically set OG:Tags using an API head() { this.$axios .get(`............`) .then((response) => { this.og_title = response.data.message.course.course_name; this.og_description = response.data.message.course.description; ...

Exploring the Interplay of Classic ASP and AJAX Variables References

When the page loads, I check for an empty session variable. If it is empty, I trigger an AJAX function to include a hidden login form with ASP script that becomes visible through JavaScript. This part of the process works smoothly. Upon submitting the for ...

How can JavaScript be effectively reused across two JSP pages for improved efficiency?

I am facing an issue with reusing a javascript function in two JSP pages. Both pages have anchors that trigger a database operation when clicked. To avoid duplicating the script, I am considering creating a separate JSP page specifically for this script an ...

Exploring the features of useEffect and setState in hook functions

Exploring the idea of utilizing React to efficiently fetch data using useEffect correctly. Currently facing a situation where data fetching is occurring constantly instead of just once and updating only when there is an input for the date period (triggeri ...

Pause for a brief moment before proceeding to the next task within the map

My situation involves having a list of usernames that represent accounts: let users = [ "user1","user2","user3","user4","user5","user6","user7" ] users.map(async (user, i) => { co ...

Converting an array of arrays into an object with an index signature: A step-by-step guide

I find myself facing a challenge where I have two types, B and A, along with an array called "a". My objective is to convert this array into type B. Type A = Array<[string, number, string]>; Type B = { [name: string]: { name: ...

Ways to prevent a single element from being included in the selection of the entire

Here is my question: I am facing an issue with a context menu that should only disappear when clicking outside of a specific row within that menu. The element I want to exclude, with the id "except", is buried deep within multiple parent elements in my co ...

Assigning a prop value in Vue using JavaScript

I am currently facing a challenge with an old legacy MVC application that contains various UI technologies such as razor pages, jQuery, and Vue native components. The issue at hand is that although the new Vue components function perfectly in isolation, we ...

Ensure form input security by implementing jQuery validation with reCAPTCHA

I have a comment submission form that adds data to a database upon submission. Below is the code snippet for the functionality: function reloadRecaptcha() { var publicKey = "*************************************"; var div = "recap"; Recaptcha. ...

Saga Redux fails to pass parameters during post requests

This is my first time using redux Saga to handle API requests. I have created an async function for a simple post request in the following way: const onLoginRequest = async (userName, password) => await fetch(`${loginApi}`, { method: 'POST', ...

When attempting to access an object within an array in JavaScript, an error is thrown stating: "TypeError: Cannot read property 'data' of undefined."

I am facing an issue while trying to access and manipulate an object within an array of objects using JavaScript in Google Apps Script. The error message I receive is: "TypeError: Cannot read property '0' of undefined" The JSON data (obtained fr ...

What is the best way to extract the text between the @ symbol and the next space using JavaScript or React?

As a beginner in programming, I am looking to extract the text following an @ symbol and preceding the next space entered by a user into an input field. For instance, consider the following input: somestring @user enters In this case, my goal is to cap ...

Issue with useEffect function not loading correctly in Gatsby production environment

I'm currently in the process of building a website with Gatsby.js. Within my component, I've incorporated animations using Gsap within the useEffect function. During debugging, everything works as expected. However, once the site is in productio ...

Guide to generating external source maps for using the Chrome debugger in Vscode with Typescript and Gulp for web development

Seeking to utilize Gulp for the development of my straightforward Typescript project that runs in the browser. When using gulp-typescript, it seems to insert modules.export into the generated js files, leading me to explore some examples involving browseri ...

Is it possible to simultaneously toggle buttons and submit a form?

I am currently working on a functionality that involves toggling the display of two buttons and submitting a form. Code toggleButtons() { var btn1 = document.getElementById("start"); var btn2 = document.getElementById("pause"); if (btn1.style. ...

Preventing page reload by using event.preventDefault() does not work with Ajax Form

I've been working on a code snippet to submit a form using Ajax without any page reloads: $( document ).on('submit', '.login_form', function( event ){ event.preventDefault(); var $this = $(this); $.ajax({ data: ...

Executing jQuery script on dynamically loaded content

My website utilizes AJAX requests to load pages dynamically. One specific page includes a marquee script that I would like to implement. Unfortunately, due to the dynamic loading of the page, the marquee script is not functioning as expected. I have come ...

The form post request cannot recognize the undefined variable

When attempting to send values through an HTML form and retrieve it in console.log, I encounter an error that says "TypeError: Cannot read property 'fName' of undefined," despite declaring it in the form name. signin.html : <!doctype html> ...

Using Jquery to detect changes in a Datalist element in an HTML5 document

This snippet illustrates the code: <input name="cmbname" type="text" id="cmbname" list="listcmbname" autocomplete="off" runat="server"> <datalist id="listcmbname"> <option data-id="1" value="a"></option> <optio ...