tscc
tscc copied to clipboard
How to include custom definition files?
We use a service called "heap", that provides just an interface in their documentation for typescript users.
In our project we have a custom @types
folder where I've been putting my own index.d.ts
files, but so far they've all been just adding things to jQuery, and only for things that already don't have definition files in DefinitelyTyped
.
In the fancybox/index.d.ts
file I have the following
/// <reference types="jquery"/>
declare interface JQueryStatic {
fancybox: FancyBoxJQueryMethods;
}
and this just kind of magically works with my tscc.spec.json
file
{
"external": {
"jquery": "$",
"sweetalert2": "Swal",
"ladda": "Ladda",
"luxon": "luxon",
"intl-tel-input": "intlTelInput",
"grecaptcha": "grecaptcha",
"big.js": "Big",
"axios": "axios",
"jszip": "JSZip",
"file-saver": "FileSaver",
},
"compilerFlags": {
"rewrite_polyfills": true,
"language_out": "ES5_STRICT",
"compilation_level": "ADVANCED_OPTIMIZATIONS",
"use_types_for_optimization": true,
"output_wrapper": "(function(){%output%})()"
}
}
and my my tsconfig.json
{
"compilerOptions": {
"alwaysStrict": true,
"strict": true,
"sourceMap": true,
"noImplicitAny": true,
"allowJs": false,
"target": "es5",
"noEmitOnError": true,
"lib": [
"es6",
"dom"
],
"baseUrl": "./",
"plugins": [
{
"name": "typescript-tslint-plugin",
"alwaysShowRuleFailuresAsWarnings": false,
"configFile": "tslint.json",
"suppressWhileTypeErrorsPresent": false,
"ignoreDefinitionFiles": true
}
]
}
}
My heap/index.d.ts
file looks like
export declare interface Heap {
track: (event: string, properties?: Object) => void;
identify: (identity: string) => void;
resetIdentity: () => void;
addUserProperties: (properties: Object) => void;
addEventProperties: (properties: Object) => void;
removeEventProperty: (property: string) => void;
clearEventProperties: () => void;
appid: string;
userId: string;
identity: string | null;
config: any;
}
declare const heap: Heap;
export default heap;
and using like this
import heap from '../@types/heap/index';
heap.identify(opts.email); // unique identifier
heap.addUserProperties({'Name': opts.name}); // other props
This works great as far as vscodes intellisense goes, but tscc fails with
TSCC: Module name ts.webcore.$001stypes.heap.index$.d$.ts was not provided as a closure compilation source
I tried adding "heap": "heap"
to my tscc externs, but that didn't help. I also played around a ton with setting the closure compiler typeRoots
, but nothing seemed to change the behavior, and I also stumbled upon this comment that makes me see that that wasn't the correct approach anyway https://github.com/microsoft/TypeScript/issues/12222#issuecomment-260417733.
I also see in the debug output it's re-writing the import as the following, where I'm sure the error is coming from.
var index_1 = goog.require('ts.webcore.$001stypes.heap.index$.d$.ts');
The gluing file being generated is named "heap.js" which contains
goog.module('ts.webcore.$001stypes.heap')
/** Generated by TSCC */
exports = heap;
This led me to try changing the tscc spec extern to "ts/webcore/@types/heap": "heap"
, but that only renames the gluing file to ts.webcore.$001stypes.heap.js
, and I'm guessing that because the name isn't ts.webcore.$001stypes.heap.index$.d$.ts'
is where the problem arises. I couldn't figure out how to right the extern in the tscc spec file to get the names to match.
Am I doing something wrong? Is there a way to reference custom type definition files?
I also tried the comment here about setting a path in the tsconfig.json to point directly to the custom type https://github.com/microsoft/TypeScript/issues/22217#issuecomment-751904666
"paths": {
"heap": ["ts/webcore/@types/heap"],
}
And then changing my import to import heap from 'heap';
, which also satisfies the intellisense, but doesn't change the error, and the gluing file turns into this
goog.module('heap')
/** Generated by TSCC */
exports = heap;
which looks like that attempt is going in the opposite direction perhaps.
Side note, but we've been using this for all of our projects since I first started making issues here (lol), and we absolutely love your tool!
In the statement
import heap from '../@types/heap/index';
the imported module name is a relative path, and it refers to a file located there. When tscc collects source files to feed to closure compiler, it looks for the above path and founds nothing (.d.ts
file do not emit .js
files), hence the error.
In order to have such modules to be considered as external, you have to provide the module's path to the spec file, like below.
{
"external": {
"./ts/webcore/@types/heap/index": "heap"
}
}
Then tscc will create gluing modules and goog.require
it whenever a file tries to import the ./ts/webcore/@types/heap/index
file. Files in different directory may use different module name to refer to the same module, because module resolution algorithm is in act here.
When a relative path (those starting with ./
or ../
) is used as a key in "external"
value in spec files, it is resolved from the spec file's location itself, not the current working directory.
In the README, I have mentioned about declaring relative path as an external module, but now I found that it is not very prominent. I guess it'd be nice to elaborate it more with some examples.