Search code examples
typescriptcommonjs

Writing Typescript for Many Import Patterns and Intellisense


I'm trying to update some javascript modules to typescript and having trouble keeping compatibility. I have some older projects in javascript using the commonjs pattern const fn = require('mod'); that rely on this module still. I've tried following the typescript guide on handling so many flavors of imports:

https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html#handling-many-consuming-import

// src/mod.ts
type FnResult = Promise<void>;
function fn(): FnResult {
    return Promise.resolve();
}

fn.fn = fn;
fn.default = fn;
module.exports = fn;

This works great when compiling for older javascript projects and most newer projects alike. tsc builds the following:

// lib/mod.js
"use strict";
function fn() {
    return Promise.resolve();
}
fn.fn = fn;
fn.default = fn;
module.exports = fn;

// lib/mod.d.ts
declare type FnResult = Promise<void>;
declare function fn(): FnResult;
declare namespace fn {
    export var fn: typeof globalThis.fn;
    var _a: typeof globalThis.fn;
    export { _a as default };
}

However, when using import fn from './mod'; in typescript, including the module's own unit tests, I get File '.../mod.ts' is not a module.ts(2306) as an intellisense error. Is there more to this "technique" I'm missing to define this as a module but still ensure compatibility?


Solution

  • It looks like I can solve this in my babel configuration by using babel-plugin-replace-ts-export-assignment. Appended my .babelrc like:

    "plugins": [
      "babel-plugin-replace-ts-export-assignment"
    ]
    

    My app.ts then looks like:

    fn.fn = fn;
    fn.default = fn;
    export = fn;
    

    It now both builds correctly for javascript commonjs pattern and my typescript unit tests don't throw intellisense errors.