Figured it out!
Initially, I was trying to import my module like this:
const qml = require('quill-marking-logic')
const { checkSentenceCombining, checkSentenceFragment, checkDiagnosticQuestion, checkFillInTheBlankQuestion, ConceptResult } = qml
because I got a TS2307: Cannot find module 'quill-marking-logic'
error when I tried to use
import { checkSentenceCombining, checkSentenceFragment, checkDiagnosticQuestion, checkFillInTheBlankQuestion, ConceptResult } from 'quill-marking-logic'
This was because I was using "module": "es6"
in my importing app's tsconfig, which by default sets the moduleResolution
option to Classic
. By explicitly setting it to node
, I was able to use the import
syntax and get my interfaces!
Original post
I've built a node module using Typescript that I am using as a dependency in another app. I have a couple of interfaces in the module that I am trying to export from the its entry point so that I can use them in my other app, but they are erased after compilation. I understand that this is part of Typescript's design, because the interfaces are used for runtime analysis, but I'm wondering if there's a way to get around it so I don't have to define them again in my other app and have to maintain the same code in two places. I'm using rollup as my bundler.
This is what the .d.ts version of my entry point looks like:
export { checkSentenceCombining } from './libs/graders/sentence_combining';
export { checkDiagnosticQuestion } from './libs/graders/diagnostic_question';
export { checkSentenceFragment } from './libs/graders/sentence_fragment';
export { checkFillInTheBlankQuestion } from './libs/graders/fill_in_the_blank';
export { Response, PartialResponse, ConceptResult, FocusPoint, IncorrectSequence, FeedbackObject, GradingObject, WordCountChange } from './interfaces/index';
That last line of exports is where the interfaces should be coming through.
Here is my tsconfig:
{
"compilerOptions": {
"target": "es5",
"module": "CommonJS",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"sourceMap": false,
"noImplicitAny": false,
"lib": [
"dom",
"es7"
],
"typeRoots": [
"node_modules/@types/"
],
"declaration": true
}
}
Here is my tsconfig for the app I'm trying to import this in to:
{
"compilerOptions": {
"outDir": "./dist/", // path to output directory
"sourceMap": true, // allow sourcemap support
"strictNullChecks": true, // enable strict null checks as a best practice
"module": "es6", // specifiy module code generation
"jsx": "react", // use typescript to transpile jsx to js
"target": "es6", // specify ECMAScript target version
"allowJs": true, // allow a partial TypeScript and JavaScript codebase
"lib": ["ES2017", "DOM"], //
"allowSyntheticDefaultImports": true // Allow import React from 'react'
}
}
And I'm pointing to the generated .d.ts file in the "typings" key in my package.json.
Yes, this is possible. To do this, export
the interfaces you'd like to make available to consumers of your module in your module's entry point file:
// in entry.ts
import { MyInterface1 } from '/path/to/interface/one';
import { MyInterface2 } from '/path/to/interface/two';
export { MyInterface1, MyInterface2 };
Then, in your code that uses this module, you can do:
import { MyInterface1, MyInterface2 } from 'my-module`;
In order for this to work, you'll need to make sure the declaration
compiler option is set to true
in your module - this causes the compiler to output a .d.ts
file that contains your module's typing information.
The last piece of the puzzle is to include a types
property in your module's "package.json" that points to this .d.ts
file:
{
"name": "my-module",
"main": "./entry.js",
"types": "./my-module.d.ts"
}
For more information about preparing a module for publishing: https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html