How to use ts file in external js file - javascript

How i can use a ts file in java script file.
I have an angular project in that i have a constant file which is environment.ts file and data is as below
export const Environment = {
PRODUCTION: false
};
and i have used one external java script library and in that library i want to access this environment.ts file i.e want to use constant.
i have tried with
var en = require('./environment.ts');
But not able to access it.

The problem probably comes from the fact that TS is compiled into JS during the build process.
Since you're just exporting the single object, it doesn't really need to be a typescript file.
Try to rename the file into 'environment.js', it shouldn't break anything and it will allow you to require it in other js files.

Try this,
import { Environment } from './environment';
Now we can access the properties like Environment.PRODUCTION

What I did is created dev.json and prod.json with my configurations.
I then imported dev.json into environment.ts and prod.json into environment.prod.ts for exporting to ts files.
I also imported dev.json into an environment.js and environment.prod.js for exporting to js files. You could also use the json directly if you want, but this will give you the flexibility to manipulate in js if you want later.
Now to update configs you just keep updating the json files.
Make sure your external js knows which env configs to read depending on how you're building/compiling it.

Related

How to include a global file type declaration in a TypeScript (Node.js) package

I'm working on a package that I am planning to publish publicly on npmjs. Let's call it the "text package".
I would like that by default when installing that package, you can import .txt files directly and get the correct type (out of the box), like this:
import text from './file.txt'
The text variable would be of type string because the package would have defined its type, using something like this (in a global.d.ts):
declare module '*.txt' {
export const text: string;
export default text;
}
If I include that global.d.ts in my package, and that I import something from this package, then I will automatically get the correct type when importing a .txt file.
But the problem is sometimes I would just need to import a .txt file without importing anything from the "text package", which is why I was wondering if there is some sort of way, as you install a package to install a global type that does not require to import anything else for the type to apply.
In other words, as soon as you install my "txt package" the declare module '*.txt' would apply to my entire project out of the box.
Is there even a way to do this, or whoever installs my package would have to declare their own global type (e.g., declarations.d.ts) to be able to import .txt files globally?
I know that even if the import type works, it will still require Webpack or another bundler to really work but this question is just about the type.
The short answer is:
TypeScript does not support Global types without importing the file referring to the type.
More details:
One example that I found doing this was Next.js - when creating a TypeScript app using npx create-next-app#latest --typescript you can start importing *.css files (for example) and get the correct type.
Where I got confused is that I originally thought that the type was coming from the next-env.d.ts but even when I deleted the file, *.css import was still working in Visual Studio code. But the reason it was, is because a file in the pages directory were importing Next.js' index.d.ts file.
Basically, in Visual Studio Code, as soon as your import a type somewhere in your project, if it's global, it will be accessible everywhere.
Workaround
So what can be done with the current TypeScript capabilities? To support new file types, you will need a file loader such as Webpack. The logical thing to do would be to add a reference to the file type declaration in the file loader itself. This way, as soon as you configure your file loader to be able to import the file, you will inherit the type:
create a txt.d.ts in our package's source directory (e.g. src) - you can use any name for the file, it's not important
if you are using eslint, add an entry to ignore the type file (e.g. 'src/*.d.ts' in your ignorePatterns option
Since you are adding a d.ts file in your source that is not managed by tsc, you need to add a script that will perform the following actions:
Copy txt.d.ts in the target directory of the compiled files for your package
Add this line at the top of your package's file loader (e.g. loader/index.d.ts: /// <reference types="../txt" />\r\n - this will link the declaration file back into your package. Note that you can add this reference to any file of your package.
This workaround will only work once you import the file referencing back to the declaration - this is the only way TypeScript can be made aware that this type exists (see https://github.com/microsoft/TypeScript/issues/49124).
Another alternative could also be to add manual steps (in a readme file) to add a global type declaration file.
to bundle global types, do the following. form typescript
specify default typings directory at typeRoots. .e.g "typeRoots": ["./src/types"].
create a file /src/types/global.d.ts in the specified directory
declare your types in the file inside declare global {} and make sure to have export {} if you don't already export anything.

typescript: using declaration files in a typescript project to expose types globally

I have recently started working with typescript.
I have a typescript project setup which has a lot of React components written with typescript.
These typescript components usually export the component itself and to make development convenient, I have extracted all the types required by this typescript component to a separate file. Now usually you would have to import these types in your component to use it, but since it was cumbersome, some one in the team came up with an idea to name these separate file containing types as types.d.ts (or whatever.d.ts). This makes the types available globally across the project, without needing to explicitly import the types anywhere.
Now, I understand that type declaration files are only required in case I am consuming a javascript component in my typescript project, and if I want to have type checking working for that javascript component. In which case, I can either get the type declaration file from outside (like, DefinitelyTyped) , or I can create a local declaration file.
This is not what i am using a declaration file here for.
But i would like to understand what are the problems with this usage?
Is it wrong to expose all the types globally (Please note that most of these types are only required internally by the component, only some are required by other components which consume this component)?
Is there going to be any problem with the compiler or the typescript setup due to this ?
I have read about a compiler option which generates the declaration files, can this setup interfere with that ?
NOTE: This separate file which is named as d.ts does not really follow any specific guidelines that may be required for declaration files. This just has some regular interface declarations
Some observations:
in a .ts file (or a d.ts file), if there is no top level export, it would be considered a global script (similar to how this works in javascript) and everything in the script would be available globally. This is how the types are exposed globally in my case (again, it does not have to be a .d.ts file)
if you a ts file and a d.ts file with the same name, the compiler ignores the d.ts file and that is why it is not possible to expose types for Component.tsx using Component.d.ts (you would need to name the d.ts file something else)
when importing an external module without type information, typescript suggests to add a d.ts file with declare module moduleName, instead of this you can also just add a regular .d.ts file with a top level export inside moduleName/index.d.ts
So, to answer my questions:
it might not be wrong to expose all the types globally used within your application, but then you have to take care of any namespacing/naming conflicts. In this case, using d.ts file is not required, this setup would just work as well with a .ts file exposing the types globally.
Another way to achieve this would be to export types from respective files and import them wherever required.
in this setup, the only problem with the compiler which may arise is when the .d.ts file is named same as the .ts file, in which case the .ts file would override and types from .d.ts would not be available globally.
the compiler generates the declaration files from ts files, and that is mostly required if you need to publish your types. In our case, the types are internal and we won't really need to generate the declarations. Our usage, as discussed, is not dependent on the file being a declaration file, it will work just as well in a .ts file and we shouldn't be using .d.ts file for this. So, no, there wouldn't be any impact.

Visual Studio Code Intellisense for JSON files imported via require

Is there a way to have intellisense in VSC work with json files imported via the require method in nodeJS?
var jsonObj = require('path/to/jsonFile.json')
I'd like for it to predict the properties of the json object imported from the file as I code.
Not possible in all instances, but when I'm creating JSON for configurations or other static data that could have been stored in a JSON file, I store it in a .js file and use the module.exports to expose it. This way the Intellisense picks it up and you get the auto-complete in VSC.
module.exports = {"data":{"foo":"bar"}}

Properties file in JavaScript / Angular

In Java I usually create application.properties in my resource folder and put configs in there.
And when I need it I just do Properties prop = new Properties(); prop.load(... my file) and then use prop.getProperty("Something")
I want to do something similar in Javascript
In my js code I have this:
// REST API Base URL
var baseUrl = "http://localhost:8083/api";
I want this to be in a application.properties file and then load the value.
How can I achive this?
Thanks
In angular 2+ projects and for a good practices you should create environments folder with one file per env like: environment.js, environment.prod.js.
and into file you can export a constant or by default like that
export const environment = {
apiUrl: '',
googleApiKey: '',
}
and you can import this environment in every file you will needed like
import { environment } from '{relativePath}/environment/environment.js'
If you create different files for every env like prod. You need to replace environment.js for env that you will be build. You have lot of info about this with webpack or other compilers.
I recommend you strongly to develop into a common.js project. It will be more friendly for you importing modules and you will have powerful possibilities of scalable app.
But the easy(Ugly) solution is:
index.html
<head>
<script src="environment.js">
<script src="app.js">
</head>
environment.js
// Declaring environment like that you will have window scoped the variable
// and you will have global access to environment with window.environment
var environment = {apiUrl: 'https://api.url:4100'}
app.js
function example(){
console.log(window.environment.apiUrl); // out https://api.url:4100
}
The approach depends on how you build and/or bundle your AngularJs application. But regardless of that, you'll need to create a config.json file to contain your settings.
If using browserify or webpack, you can import that file via require(...), otherwise you can simply request it via ajax before your app bootstraps.
In any of these cases, the best way to use the configuration data throughout your app is to define it as a constant at the bootstrap phase: app.constant('CONFIG', configData);, assuming that configData is a variable that contains the data from your config.json file.
Then you can use dependency injection to provide CONFIG to all your controllers, services and directives.

Angular2 - require module on client side

In the context of a Node.js / Express / Angular2 / typescript (IDE=Visual Studio) app, I am trying to load a third party .js utility (packery) onto the client side (for use in a directive). Someone made typescript definitions for it. The d.ts file looks like:
declare module "packery" {
interface PackeryOptions { stuff... }
class Packery { stuff .... }
export = Packery;
}
I refer to this d.ts file, tell the browser where the .js packery script lives, and then import the module as such:
import Packery = require('packery');
This compiles without complaint. However, upon running, the browser attempts (and fails) to find "packery" at http://localhost/packery as opposed to knowing packery is an imported library. This is in contrast to the other import statements I have made on the client such as:
import {Http, HTTP_PROVIDERS} from 'angular2/http';
which work - as far as I can tell the only two pieces of information I gave it for those were also a d.ts file and the location of the .js file, just like packery. But, I must be missing something. Have tried many combinations of file locations and linking and can't get it to work. How can I get the proper linking to "packery"?
Thanks!
I found a workaround for this and thought I'd post in case it helps anyone, although I am still having difficulty with the setup posed in the original question, that is, getting statements of the type:
import foo = require('foo')
to run on the CLIENT side. These work for me in node.js on the server, but on the client, for third party libraries that have been loaded via a script tag, I cannot get it to work, even if I add mapping entries to the system.js config file, irrespective of if I point to a .js file or a d.ts file.
Anyway, what does work is if you load the library using the script tag, then in your IDE put a reference path as such at the top of the CLIENT side code
/// <reference path="foo.d.ts" />
and ensure that your d.ts file does not declare a module/namespace but rather exports methods etc. directly. This lets the IDE compile without complaint, and the client side code is able to access the third party library.
However, I'm not sure if it is preferable / best practices to do what I did or if one should be configuring System.js somehow.
Typings are empty definitions of js libraries that aren't written in a typed language. They are only useful in development for IDEs hints and stuff, in your app, you'll still use the library as you normally would, adding the js file in your index.html or w/e you load your js files from.

Categories

Resources