typescript can't resolve non-relative path in import - import

I have project structure like this
|--src
|--app.component
|--index.ts
|--home.component
|--index.ts
|--tsconfig.json
|--webpack.config.js
And I'm trying to do stuff below in app.component-index.ts
import { HomeComponent } from 'components/home.component'
Typescript couldn't find this module and throws
error TS2307: Cannot find module 'home.component'
Typescript docs say next:
A non-relative import to moduleB such as import { b } from "moduleB",
in a source file /root/src/folder/A.ts, would result in attempting the
following locations for locating "moduleB":
/root/src/folder/moduleB.ts
/root/src/moduleB.ts
/root/moduleB.ts
/moduleB.ts
So for my case I expect it would be like
/src/components/app.component/components/home.component
/src/components/components/home.component
/src/components/home.component
Thanks in advance.
P.S. In my webpack.config I've setted root.resolve to src and everything bundles correct. Typescript-loader prints errors to terminal but everything is bundled and works correctly

So I can guess at the "why" portion of this but I'm relatively new to TypeScript. I have gotten this to work though so I'll try explaining based on that solution as best I can.
What you expect based on the TypeScript Docs would be mostly correct if:
'components/home.component'
were treated as a 'Non-relative import'. I'm fairly certain (based on the solution that worked for me) that TypeScript treats it as an absolute path from the 'compilerOptions.baseUrl' field in your tsconfig.json.
What worked for me was to set it like so:
{
"compilerOptions": {
"baseUrl": ".",
// Other options
}
}
Which essentially tells TypeScript to try and find something like
'components/home.component'
by looking in the same directory as the tsconfig.json file for a directory called 'components' and then to look for a file/directory within it called 'home.component'.
So if your structure looks like:
|--src
|--app.component
|--index.ts
|--home.component
|--index.ts
|--tsconfig.json
|--webpack.config.js
And you set baseUrl to "." you would probably need to format your import like
import { HomeComponent } from 'src/home.component'

Related

Specifying window (global) variable type hinting in VSCode from external JS file without typescript

This may be a silly question but I really don't know where to look.
I'm creating a browser testing environment for a pretty large-scale API written in typescript. This API uses esbuild to build the typescript files into a /dist/ folder with a single index.js entry-point and its appropriate d.ts file.
I've created a /tests/ folder to hold some browser files that includes an index.html file with Mocha and Chai imported. It also imports /dist/index.js which is set globally to a window.myAPI variable.
In /tests/index.html:
import * as myAPI from "./dist/index.js"
Alongside index.html in the tests folder, there are separate JS files included for different tests that run things on window.myAPI... to do assertion tests.
search.test.js
book.test.js
navigate.test.js
I then run a server to host at the root. These separate tests are then imported from /tests/index.html. The separate tests look like this inside:
const { chai, mocha } = window;
const { assert } = chai;
describe("Search", function() {
describe("Setup", function() {
it("Setting URL should work", function() {
const call = myAPI.someCall()
assert.ok(call);
});
});
});
mocha.run();
Everything works, but I have no code hinting for myAPI. I'd like to be able to see what functions are available when I type myAPI, and what parameters they take, and what they should return - along with all my comments on each function.
In typescript you can do things like ambient declarations, but I don't want to make my tests typescript because then I add an unnecessary build step to the tests. But it would be as easy as:
/// <reference path = "/dist/index.d.ts" />
How can I tell VSCode that window.myAPI is an import of /dist/index.js and should import the types as well so I can see them ?
I'm open to different solutions to this, but I feel like this should be pretty simple. I don't know if ESLint is capable of doing something like this, but I tagged it because I feel it's relevant.
Thanks!

Luxon not running in stackblitz with typescript

I'm trying to make a luxon example in stackblitz, but the imports are not working.
The luxon library and its types are added, and it is imported at the beginning of the file:
However I get the message that it is undefined!
I tried to find other examples of stackblitz (google: "luxon stackblitz") however none of them seem to work or use and old version, which is imported via CDN
Do I somehow have to add the whole luxon library to the project?
Code (super simple)
// Import stylesheets
import './style.css';
import { DateTime } from 'luxon';
// Write TypeScript code!
const appDiv: HTMLElement = document.getElementById('app');
appDiv.innerHTML = `luxon sample -->"${DateTime.now()}"<--`;

Go to definition, go to implementation, autogenerate import for Ember

Im using Ember with VS Code.
What I need is to generate import string on a fly when I encounter dependency. For example I write someting like:
#tracked isLarge = false;
But I don’t have “#tracked” imported yet. So the otion could be to set the coursor on #tracked, press something like “Action + .” and pick “generate import”. It should generate import string:
import { tracked } from '#ember/tracking';
But it doesn’t work out of the box. How can I do that?
UPDATE: the same question about:
go to definition
go to implementation
cmd+click to navigate to implementation/component
You can use the extension My Code Actions
You can create actions that just insert the text independent of an error.
"my-code-actions.actions": {
"[javascript]": {
"import tracked": {
"where": "insertAfter",
"insertFind": "^import",
"text": "import { tracked } from '#ember/tracking';\n"
}
}
}
The key combo to use is the Code Action combo: Ctrl+.
If you get a diagnostic (PROBLEM panel, and squiggle) you can use that to further customize the action and you can use text from the diagnostics message.
I'm current adding the possibility to make multiple edits in an action and to use further customization and generalization.
"Ember Language Server" brings some solution. But it works mostly with library code that has .d.ts typings.
In case of custom JS code it still doesn't work.
So there is no straight solution. Only 2 ways:
Write .d.ts typing for custom code JS files
Move project to typescript

What Path is the Babel Plugin module-alias Actually Using?

I'm trying to use Babel's "module-alias" plug-in with the "proxyquire" testing library, but I'm not having a lot of luck.
Library Backstory
(feel free to skip if you are familiar with both module-alias/proxyquire)
Proxyquire let's you mock out a module's dependencies for testing, like so:
const someFunctionToTest =
proxyquire(pathToSomeFunctionToTestsModule, {
pathToDependency: fakeVersionOfDependency
});
Babel's module-alias plugin let's you make your import paths more convenient and consistent. For instance, I can specify (in .babelrc):
"plugins": [
["module-alias", [
{ "src": "./", "expose": "~" }
]],
and then instead of having to type (when importing from a module nested three directories deep) require('../../../someModule') I can just typerequire('~/someModule')`.
The Problem
My problem is, they don't work together. If I havesomeModule that depends on someDependency:
// src/someModule.js
const someDependency = require('~/src/someDependency');
doSomethingWith(someDependency);
and then I want to test someModule with a mock version of someDependency, I should be able to do:
const proxiedSomeModule =
proxyquire('~/src/someModule', {
'~/src/someDependency': fakeVersionOfSomeDependency
});
... but proxyquire tells me `Error: Cannot find module '~/src/someModule'.
Presumably ("behind the scenes") Babel is converting '~/src/someModule' into its real path, so when Proxyquire looks for the aliased path it can't find it.
The Question
My question is: is there any way I can find out what the real path of '~/src/someModule' is, after Babel converts it (ie. when proxyquire deals with it)? Or alternatively is there any way to get proxyquire to just work with the aliased paths?
It turns out the "real" path (for '~/someModule') generated by module resolver is just the ../../someModule path. However, it also turns out that there is no need to convert paths by hand.
The module resolver plug-in will convert the arguments to any functions on its transformFunctions list. This means that you can convert any string to its non-aliased form by doing the following:
Define a simple passthrough function, e.g. const resolveModulePath = path => path;
Add that function (along with proxyquire) to the transformFunctions list in .babelrc:
["module-resolver", {
"transformFunctions": ["proxyquire", "resolveModulePath"]
}]
Wrap any paths which aren't arguments to a function with resolveModulePath:
proxyquire('~/some/path/someModule', {
[resolveModulePath('~/some/other/path')]: {
someFunction: fakeSomeFunction
}
})
Note that the first path in the above doesn't need to be escaped, as its an argument to a transformed function. Only the second path ('~/some/other/path') needs to be wrapped, because it's part of an object which is an argument; the string itself isn't an argument, until it's wrapped.
For further info see: https://github.com/tleunen/babel-plugin-module-resolver/issues/241#issuecomment-350109168

Import .jsx files with SystemJS

Since the JSX plugin is deprecated I've been struggling to have Babel handle my jsx files. I finally managed to convince SystemJS to load my app with:
System.import('scripts/app.jsx!babel')
But this doesn't import any imported jsx files like:
import Login from './components/Login' // File is Login.jsx
With the old plugin this worked but now I am not sure how to get it working now.
One step in the right direction would be adding this to your config:
"packages": {
"components": { // Packages could of course be replaced with what you want
// to affect. Even "." is valid.
meta: {
'*.jsx': {
loader: 'babel'
}
}
}
}
This allows you to load files as such: import .. from './components/Login.jsx'.
You could take this one step further by adding "defaultExtension": "jsx" under "components". I'd only use this if the folder/modules was jsx-only though. That would allow you to import as import .. from './components/Login' as you wanted to.