I can see how to use addExtraLib
in Monaco to add an ambient declaration file. What's not clear is how to use this function with an external declaration file so that Typescript code in the editor can do a:
import * as External from "external"
External.foo();
On the Monaco set-up side, this doesn't seem to work:
// compiler options
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2016,
allowNonTsExtensions: true,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
module: monaco.languages.typescript.ModuleKind.CommonJS,
noEmit: true,
noLib: true,
typeRoots: ["node_modules/@types"]
});
// extra libraries
monaco.languages.typescript.typescriptDefaults.addExtraLib(
'export declare function foo():string;', 'node_modules/@types/external/index.d.ts');
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
noSemanticValidation: false,
noSyntaxValidation: false
Joe's answer didn't work for me, fixed by prefixing the external type definition file path with file:///
Here's an updated example for the playground:
monaco.languages.typescript.typescriptDefaults.addExtraLib(
'export declare function add(a: number, b: number): number',
'file:///node_modules/@types/math/index.d.ts'
);
const model = monaco.editor.createModel(
`import {add} from 'math';\nconst x = add(3, 5);\n`,
'typescript',
monaco.Uri.parse('file:///main.tsx')
);
monaco.editor.create(document.getElementById('container'), {model});
It's not necessary to provide the compiler options and diagnostic options.
After playing around a little I found a solution. Basically, the file has to be loaded using createModel
with an explicit file URL. If you do this then the relative file path for node_module/@types
works. Here's my working solution that can be used in the playground:
// compiler options
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2016,
allowNonTsExtensions: true,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
module: monaco.languages.typescript.ModuleKind.CommonJS,
noEmit: true,
typeRoots: ["node_modules/@types"]
});
// extra libraries
monaco.languages.typescript.typescriptDefaults.addExtraLib(
`export declare function next() : string`,
'node_modules/@types/external/index.d.ts');
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
noSemanticValidation: false,
noSyntaxValidation: false
})
var jsCode = `import * as x from "external"
const tt : string = x.dnext();`;
monaco.editor.create(document.getElementById("container"), {
model: monaco.editor.createModel(jsCode,"typescript",new monaco.Uri("file:///main.tsx")),
});
As of April 2021 ([email protected]
), I wasn't able to get either of the prior solutions working without some additional details based on monaco-editor#2295, monaco-editor#1839, and https://stackoverflow.com/a/63349650. My use case required making type definitions available from several existing NPM packages (not just arbitrary paths to files) and this may have affected the solution. To summarize, I needed to:
.d.ts
files from each package into a single file. TypeScript doesn't make this easy, and so instead I used dts-bundle-generator, but other solutions exist..d.ts
content for each package using raw-loader or other plain-text loading alternatives.addExtraLib
with the source for each module, adding an explicit declare module 'module-name'
to the source code.Full example below:
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import source1 from '!!raw-loader!./types/package-one.d.ts';
import source2 from '!!raw-loader!./types/package-two.d.ts'
monaco.languages.typescript.typescriptDefaults.addExtraLib(
`declare module '@my-project/package-one' { ${source1} }`,
'file:///node_modules/@my-project/package-one/index.d.ts' // irrelevant?
);
monaco.languages.typescript.typescriptDefaults.addExtraLib(
`declare module '@my-project/package-two' { ${source2} }`,
'file:///node_modules/@my-project/package-two/index.d.ts' // irrelevant?
);
monaco.editor.create(document.getElementById('root'), {
value: `
import { Foo } from '@my-project/package-one';
const foo = new Foo();
`,
language: 'typescript',
theme: 'vs-dark'
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With