Why angular model interfaces are exported? - javascript

In angular - the models (model interfaces) are declared like so:
export interface PersonInterface {
id: number;
name: string;
}
and then in some other component,service etc. your import this interface and use it like so:
...
import { PersonInterface } from './blabla';
...
export class SomeService {
person: PersonInterface;
}
So my question is - what is the purpose of using export in the declaration of the interface?
interface PersonInterface {
id: number;
name: string;
}
If I don't use export - I can still use it in the service and I even do not need to import it:
export class SomeService {
person: PersonInterface;
}
Everything works fine, no errors and from the IDE I can go to the declaration if the interface (Ctrl+Click over the interface name). Am I missing something?
Cheers

This goes to a long story of javascript history. In early ages you had to manually specify your javascript files using <script src="name.js"> tag with the exact order - top to bottom. After the script is attached all it's declarations like var a = 5 or function util(){} will be available for all the scripts below it and globally. It was very hard to hide this declarations from the global scope to achieve encapsulation, so there became a need to create something new.
Later on the es modules arrived. In order to use some function from other script, you had to export it at the very end of that script. That means that all the other, non-exported declarations (functions and variables), were encapsulated (hidden) from other scripts. This led to more resilient scripts with some defense from accident modifications (imagine someone uses a bunch of scripts for the first time, it would be a nightmare to analyze 10+ scripts without any docs). The script with export declaration looked like:
var a = 5;
function b(){};
module.exports = {
a: a,
b: b
}
In 2012s the Typescript was created. Besides all it's beautiful capabilities like static types, proper type-checking and syntax sugar, it also provided a better way to export/import functions, variables and classes. The syntax became:
import Something from '../other.script' for default exports
// other.script.ts contents
export default const A = '5'; // this will be imported in other file
import {exactOne, exactTwo} from '../other.script' for non-default exports
// other.script.ts contents
export const exactOne = 1;
export const exactTwo = 2;
export const exactThree = 3; // this is NOT imported above, but it's possible to import this const.
const exactFour = 4; // this const cannot be imported at all
import * as AllTogether from '../other.script' for bulk import.
// other.script.ts contents
export const a = 'a';
export const b = 'b';
// the AllTogether variable above will be imported like {a: 'a', b: 'b'}
Hope this helped!

Related

How do I import an IIFE-based JavaScript module into an Angular TypeScript app?

So I have a third-party SDK written as an oldschool IIFE based module. In other words it looks something like this:
var ThirdPartySDK = (function() {
var export = {};
// Add some methods to export
return export;
})();
You would then be expected to use it by referencing it on the global scope like this:
<html>
<body>
<script src="lib/ThirdPartySDK.js">
<script>
ThirdPartySDK.foo();
<\script>
<\body>
<\html>
I could still use it this way of course, but is that really the best practice with Angular and TypeScript? Is there some way to set things up with angular/TypeScript/webpack so that I can use a proper import statement? Something like this:
import { ThirdPartySDK } from '../lib/ThirdPartySDK.js';
ThirdPartySDK.foo();
The best way to have a proper import statement for the actual value of ThirdPartySDK is to refactor the script to a module that exports this value. The following snippet allows you to use the import statement as showed:
export const ThirdPartySDK = {
foo() { console.log('Doing foo'); }
};
For big libraries refactoring is not always that easy, so I see 2 approaches that do not involve too much refactoring:
1. Export the ThirdPartySDK variable
You could simply make a module out of the IIFE file by exporting the current IThirdPartySDK variable (returned by the IIFE), and then import it as you showed:
export const ThirdPartySDK = (function() {
var _export = {};
// Add some methods to export
return _export;
})();
Note that if you want to have some useful information about the shape of ThirdPartySDK you would have to add a type annotation to the const declaration, and if SomeType (see below) does not yet exist you'll have to write it yourself:
export const ThirdPartySDK: SomeType = (function() {
// ...
At this point Typescript will start to complain about the IIFE expression not being assignable to SomeType; the quick 'solution' to tell typescript to pretend the expression evaluates to a value of type SomeType using the as keyword:
export const ThirdPartySDK: SomeType = (function() {
// ...
})() as SomeType;
2. Keep the <script> tag and declare the variable
Another option it to keep the script tag, import nothing, and declare the variable and its expected type in typescript:
(But also in this case you might have to provide type definitions yourself)
interface SomeType {
// SDK type shape goes here...
}
declare const ThirdPartySDK: SomeType;
You can wrap the third-party SDK in a TypeScript module using a hack with eval.
Let's say that ThirdPartySDK.js looks like this:
var ThirdPartySDK = (function () {
var exports = {
foo: function () { console.log("Hello, world!"); }
};
return exports;
})();
You would then create a ThirdPartySDK-wrapper.ts module that looks something like this:
import * as fs from 'fs';
const script = fs.readFileSync('../lib/ThirdPartySDK.js').toString();
global.eval(script);
//#ts-ignore
export default ThirdPartySDK;
The #ts-ignore directive is required to keep the TypeScript compiler from complaining about not finding a declaration for the ThirdPartySDK variable (it is declared in the script executed through eval).
You can then import ThirdPartySDK through the wrapper module:
import ThirdPartySDK from './wrapper';
ThirdPartySDK.foo(); // Console output: "Hello, world!"
Note that this wrapper only works for applications running in Node.js, since it uses fs.fileReadSync to get the contents of the script.
If you're going to use it in a browser, you will need some other way to retrieve the script. You could probably use frameworks such as WebPack to bundle the ThirdPartySDK script as a string value that you can require in the wrapper module.

Where to put a function that is relevant to a type?

How do you structure your code when you solve similar problems?
I have an interface that just defines what js objects should look like
interface Secured {
security: string;
}
And also I have a function that checks whether the object inplements my interface
const isSecured: (x: any) => x is Secured = ......
I don't know how people structure their code in these situations but I have an idea
class Secured {
static Type = interface......
static isSecured = .....
}
But this doesn't look good, I think
Usually the code is structured using modules.
It looks like Secured and isSecured are always going to be used together, so it seems natural to
put them in one module, for example in secured.ts.
When you have more than one things exported from a module, you can use named exports for all the things:
export interface Secured {
security: string;
}
export const isSecured: (x: any) => x is Secured = ......
Then, when importing from that module, you can use namespace import to have Secured and isSecured available in the namespace of your choice:
import * as Secured from '.../relative-path-to/secured';
// here we choose Secured as namespace name
let s: Secured.Secured | SomethingElse;
if (Secured.isSecured(s)) {
}
Or you can use named imports and rename some of them:
import {Secured as SecuredType, isSecured} from '.../relative-path-to/secured';
let s: SecuredType | SomethingElse;
if (isSecured(s)) {
}

What is the difference between " import {foo} form './foo' " and " import foo form './foo' " [duplicate]

It seems to be obvious, but I found myself a bit confused about when to use curly braces for importing a single module in ES6. For example, in the React-Native project I am working on, I have the following file and its content:
File initialState.js
var initialState = {
todo: {
todos: [
{id: 1, task: 'Finish Coding', completed: false},
{id: 2, task: 'Do Laundry', completed: false},
{id: 2, task: 'Shopping Groceries', completed: false},
]
}
};
export default initialState;
In the TodoReducer.js, I have to import it without curly braces:
import initialState from './todoInitialState';
If I enclose the initialState in curly braces, I get the following error for the following line of code:
Cannot read property todo of undefined
File TodoReducer.js:
export default function todos(state = initialState.todo, action) {
// ...
}
Similar errors also happen to my components with the curly braces. I was wondering when I should use curly braces for a single import, because obviously, when importing multiple component/modules, you have to enclose them in curly braces, which I know.
The Stack Overflow post at here does not answer my question, instead I am asking when I should or should not use curly braces for importing a single module, or I should never use curly braces for importing a single module in ES6 (this is apparently not the case, as I have seen single import with curly braces required).
This is a default import:
// B.js
import A from './A'
It only works if A has the default export:
// A.js
export default 42
In this case it doesn’t matter what name you assign to it when importing:
// B.js
import A from './A'
import MyA from './A'
import Something from './A'
Because it will always resolve to whatever is the default export of A.
This is a named import called A:
import { A } from './A'
It only works if A contains a named export called A:
export const A = 42
In this case the name matters because you’re importing a specific thing by its export name:
// B.js
import { A } from './A'
import { myA } from './A' // Doesn't work!
import { Something } from './A' // Doesn't work!
To make these work, you would add a corresponding named export to A:
// A.js
export const A = 42
export const myA = 43
export const Something = 44
A module can only have one default export, but as many named exports as you'd like (zero, one, two, or many). You can import them all together:
// B.js
import A, { myA, Something } from './A'
Here, we import the default export as A, and named exports called myA and Something, respectively.
// A.js
export default 42
export const myA = 43
export const Something = 44
We can also assign them all different names when importing:
// B.js
import X, { myA as myX, Something as XSomething } from './A'
The default exports tend to be used for whatever you normally expect to get from the module. The named exports tend to be used for utilities that might be handy, but aren’t always necessary. However it is up to you to choose how to export things: for example, a module might have no default export at all.
This is a great guide to ES modules, explaining the difference between default and named exports.
I would say there is also a starred notation for the import ES6 keyword worth mentioning.
If you try to console log Mix:
import * as Mix from "./A";
console.log(Mix);
You will get:
When should I use curly braces for ES6 import?
The brackets are golden when you need only specific components from the module, which makes smaller footprints for bundlers like webpack.
Dan Abramov's answer explains about the default exports and named exports.
Which to use?
Quoting David Herman:
ECMAScript 6 favors the single/default export style, and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise.
However, in TypeScript named export is favored because of refactoring. Example, if you default export a class and rename it, the class name will change only in that file and not in the other references, with named exports class name will be renamed in all the references.
Named exports is also preferred for utilities.
Overall use whatever you prefer.
Additional
Default export is actually a named export with name default, so default export can be imported as:
import {default as Sample} from '../Sample.js';
If you think of import as just syntax sugar for Node.js modules, objects, and destructuring, I find it's pretty intuitive.
// bar.js
module = {};
module.exports = {
functionA: () => {},
functionB: ()=> {}
};
// Really all that is is this:
var module = {
exports: {
functionA, functionB
}
};
// Then, over in foo.js
// The whole exported object:
var fump = require('./bar.js'); //= { functionA, functionB }
// Or
import fump from './bar' // The same thing - object functionA and functionB properties
// Just one property of the object
var fump = require('./bar.js').functionA;
// Same as this, right?
var fump = { functionA, functionB }.functionA;
// And if we use ES6 destructuring:
var { functionA } = { functionA, functionB };
// We get same result
// So, in import syntax:
import { functionA } from './bar';
Summary ES6 modules:
Exports:
You have two types of exports:
Named exports
Default exports, a maximum one per module
Syntax:
// Module A
export const importantData_1 = 1;
export const importantData_2 = 2;
export default function foo () {}
Imports:
The type of export (i.e., named or default exports) affects how to import something:
For a named export we have to use curly braces and the exact name as the declaration (i.e. variable, function, or class) which was exported.
For a default export we can choose the name.
Syntax:
// Module B, imports from module A which is located in the same directory
import { importantData_1 , importantData_2 } from './A'; // For our named imports
// Syntax single named import:
// import { importantData_1 }
// For our default export (foo), the name choice is arbitrary
import ourFunction from './A';
Things of interest:
Use a comma-separated list within curly braces with the matching name of the export for named export.
Use a name of your choosing without curly braces for a default export.
Aliases:
Whenever you want to rename a named import this is possible via aliases. The syntax for this is the following:
import { importantData_1 as myData } from './A';
Now we have imported importantData_1, but the identifier is myData instead of importantData_1.
In order to understand the use of curly braces in import statements, first, you have to understand the concept of destructuring introduced in ES6
Object destructuring
var bodyBuilder = {
firstname: 'Kai',
lastname: 'Greene',
nickname: 'The Predator'
};
var {firstname, lastname} = bodyBuilder;
console.log(firstname, lastname); // Kai Greene
firstname = 'Morgan';
lastname = 'Aste';
console.log(firstname, lastname); // Morgan Aste
Array destructuring
var [firstGame] = ['Gran Turismo', 'Burnout', 'GTA'];
console.log(firstGame); // Gran Turismo
Using list matching
var [,secondGame] = ['Gran Turismo', 'Burnout', 'GTA'];
console.log(secondGame); // Burnout
Using the spread operator
var [firstGame, ...rest] = ['Gran Turismo', 'Burnout', 'GTA'];
console.log(firstGame);// Gran Turismo
console.log(rest);// ['Burnout', 'GTA'];
Now that we've got that out of our way, in ES6 you can export multiple modules. You can then make use of object destructuring like below.
Let's assume you have a module called module.js
export const printFirstname(firstname) => console.log(firstname);
export const printLastname(lastname) => console.log(lastname);
You would like to import the exported functions into index.js;
import {printFirstname, printLastname} from './module.js'
printFirstname('Taylor');
printLastname('Swift');
You can also use different variable names like so
import {printFirstname as pFname, printLastname as pLname} from './module.js'
pFname('Taylor');
pLanme('Swift');
Usually when you export a function you need to use the {}.
If you have
export const x
you use
import {x} from ''
If you use
export default const x
you need to use
import x from ''
Here you can change X to whatever variable you want.
The curly braces ({}) are used to import named bindings and the concept behind it is destructuring assignment
A simple demonstration of how import statement works with an example can be found in my own answer to a similar question at When do we use '{ }' in javascript imports?.
If there is any default export in the file, there isn't any need to use the curly braces in the import statement.
if there are more than one export in the file then we need to use curly braces in the import file so that which are necessary we can import.
You can find the complete difference when to use curly braces and default statement in the below YouTube video.
21. ES6 Modules. Different ways of using import/export, Default syntax in the code. ES6 | ES2015
The curly braces are used only for import when export is named. If the export is default then curly braces are not used for import.
For a default export we do not use { } when we import.
For example,
File player.js
export default vx;
File index.js
import vx from './player';
File index.js
File player.js
If we want to import everything that we export then we use *:

Typescript module factory pattern

There is a well-known approach in node.js to leverage the module factory pattern. For, example:
m.js
function factoryMethod(module) {
// doing some stuff and returning object initialized with module parameter
}
app.js
var o = require('./m')(module);
// using o
How can I do the same in typescript. Actually, creating m.ts is not a problem:
m.ts
function factoryMethod(module: NodeModule): any {
// doing some stuff
}
export = factoryMethod;
But how should I use import syntax to use this module factory method like in javascript?
I'm not sure I quite get this common pattern. You're passing the module object from one module into another? All kinds of other objects are passed around like this, (e.g. app, db), but I don't like the idea of passing around the module object. I'd be tempted to call it an anti-pattern. Surely the module object should stay in the module to which it belongs.
That said, if you just want to import and call a function on the same line, you could do this using Node's require() function, just like regular JavaScript. Let's say you are passing an Express app rather than module.
const o = require('./m')(app);
However, you lose type-safety with this; o will be of type any. You would have to explicitly define the type of o.
const o: Module = require('./m')(app);
This is a bit silly. In fact, Module is likely to be defined in the module you are requiring anyway, so it is likely also self-defeating. My suggestion is this. Don't expect to use the same patterns you are used to in plain JS in TypeScript, which has its own patterns.
One thing you could do is import the function at the top, and then call it later. TypeScript uses ES2015-style modules, which don't allow you to import a function and call it on the same line. You will have to rewrite both files, since export = is not valid in ES2015.
// m.ts
interface Module {
// properties, methods, etc.
}
export function factoryMethod(app: Express.Application): Module {
let module = {};
// Initialize module methods, properties, etc.
return module;
}
The interface allow type inference in app.ts, which is an improvement of a kind.
// app.ts
import {factoryMethod} from './m';
// ...
let o = factoryMethod(app);
But this is still very silly. We don't need to define an interface and all that nonsense. Instead, we can use a class. Classes are very often the answer in TypeScript, and you'll find that most patterns in TypeScript involve them.
// m.ts
export class Module {
constructor(private app: Express.Application) { }
cache: string[];
someMethod(): Promise<Express.Response> {
// do something with this.app
}
}
And then in app.ts
import {Module} from './m';
// ...
let o = new Module(app);
Now we don't have to worry about interfaces and all that. The class itself is a type. This is quite a bit different from what you are likely to see in a typical Node app, but it is the sort of pattern you find all the time in TypeScript.
Hopefully that gives you some ideas.
import {factoryMethod} from './m.ts'
let module = factpryMethod('module');
I know this question is fairly old but I came across the same issue when converting an existing JS project to TypeScript that makes use of this pattern.
Instead of having to pre-define the module definition in an interface we can use the ReturnType helper to get a type definition of the return type of a function!
This is what the module might look like:
function initModule(arg1: number, arg2: number) {
function functionA() {
return arg1;
}
function functionB() {
return arg2;
}
return {
functionA,
functionB,
};
}
export default initModule;
export type SampleModule = ReturnType<typeof initFactory>;
And here is how we could use it:
import initModule, { SampleModule } from './factory';
const newModule: SampleModule = initModule(1, 2);
newModule.functionA(); // 1
newModule.functionB(); // 2
Seriously, how cool is TypeScript? :)

TypeScript ES6 import module "File is not a module error"

I am using TypeScript 1.6 with ES6 modules syntax.
My files are:
test.ts:
module App {
export class SomeClass {
getName(): string {
return 'name';
}
}
}
main.ts:
import App from './test';
var a = new App.SomeClass();
When I am trying to compile the main.ts file I get this error:
Error TS2306: File 'test.ts' is not a module.
How can I accomplish that?
Extended - to provide more details based on some comments
The error
Error TS2306: File 'test.ts' is not a module.
Comes from the fact described here http://exploringjs.com/es6/ch_modules.html
17. Modules
This chapter explains how the built-in modules work in ECMAScript 6.
17.1 Overview
In ECMAScript 6, modules are stored in files. There is exactly one
module per file and one file per module. You have two ways of
exporting things from a module. These two ways can be mixed, but it is
usually better to use them separately.
17.1.1 Multiple named exports
There can be multiple named exports:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
...
17.1.2 Single default export
There can be a single default export. For example, a function:
//------ myFunc.js ------
export default function () { ··· } // no semicolon!
Based on the above we need the export, as a part of the test.js file. Let's adjust the content of it like this:
// test.js - exporting es6
export module App {
export class SomeClass {
getName(): string {
return 'name';
}
}
export class OtherClass {
getName(): string {
return 'name';
}
}
}
And now we can import it in these three ways:
import * as app1 from "./test";
import app2 = require("./test");
import {App} from "./test";
And we can consume imported stuff like this:
var a1: app1.App.SomeClass = new app1.App.SomeClass();
var a2: app1.App.OtherClass = new app1.App.OtherClass();
var b1: app2.App.SomeClass = new app2.App.SomeClass();
var b2: app2.App.OtherClass = new app2.App.OtherClass();
var c1: App.SomeClass = new App.SomeClass();
var c2: App.OtherClass = new App.OtherClass();
and call the method to see it in action:
console.log(a1.getName())
console.log(a2.getName())
console.log(b1.getName())
console.log(b2.getName())
console.log(c1.getName())
console.log(c2.getName())
Original part is trying to help to reduce the amount of complexity in usage of the namespace
Original part:
I would really strongly suggest to check this Q & A:
How do I use namespaces with TypeScript external modules?
Let me cite the first sentence:
Do not use "namespaces" in external modules.
Don't do this.
Seriously. Stop.
...
In this case, we just do not need module inside of test.ts. This could be the content of it adjusted test.ts:
export class SomeClass
{
getName(): string
{
return 'name';
}
}
Read more here
Export =
In the previous example, when we consumed each validator, each module only exported one value. In cases like this, it's cumbersome to work with these symbols through their qualified name when a single identifier would do just as well.
The export = syntax specifies a single object that is exported from the module. This can be a class, interface, module, function, or enum. When imported, the exported symbol is consumed directly and is not qualified by any name.
we can later consume it like this:
import App = require('./test');
var sc: App.SomeClass = new App.SomeClass();
sc.getName();
Read more here:
Optional Module Loading and Other Advanced Loading Scenarios
In some cases, you may want to only load a module under some conditions. In TypeScript, we can use the pattern shown below to implement this and other advanced loading scenarios to directly invoke the module loaders without losing type safety.
The compiler detects whether each module is used in the emitted JavaScript. For modules that are only used as part of the type system, no require calls are emitted. This culling of unused references is a good performance optimization, and also allows for optional loading of those modules.
The core idea of the pattern is that the import id = require('...') statement gives us access to the types exposed by the external module. The module loader is invoked (through require) dynamically, as shown in the if blocks below. This leverages the reference-culling optimization so that the module is only loaded when needed. For this pattern to work, it's important that the symbol defined via import is only used in type positions (i.e. never in a position that would be emitted into the JavaScript).
Above answers are correct. But just in case...
Got same error in VS Code. Had to re-save/recompile file that was throwing error.
How can I accomplish that?
Your example declares a TypeScript < 1.5 internal module, which is now called a namespace. The old module App {} syntax is now equivalent to namespace App {}. As a result, the following works:
// test.ts
export namespace App {
export class SomeClass {
getName(): string {
return 'name';
}
}
}
// main.ts
import { App } from './test';
var a = new App.SomeClass();
That being said...
Try to avoid exporting namespaces and instead export modules (which were previously called external modules). If needs be you can use a namespace on import with the namespace import pattern like this:
// test.ts
export class SomeClass {
getName(): string {
return 'name';
}
}
// main.ts
import * as App from './test'; // namespace import pattern
var a = new App.SomeClass();
In addition to A. Tim's answer there are times when even that doesn't work, so you need to:
Rewrite the import string, using the intellisense. Sometimes this fixes the issue
Restart VS Code
I had this issue and I had forgotten to export the Class.
In addition to Tim's answer, this issue occurred for me when I was splitting up a refactoring a file, splitting it up into their own files.
VSCode, for some reason, indented parts of my [class] code, which caused this issue. This was hard to notice at first, but after I realised the code was indented, I formatted the code and the issue disappeared.
for example, everything after the first line of the Class definition was auto-indented during the paste.
export class MyClass extends Something<string> {
public blah: string = null;
constructor() { ... }
}
Just in case this may works for you as it did form me, i had this files
//server.ts
class Server{
...
}
exports.Server = Server
//app.ts
import {Server} from './server.ts'
And this actually raised an error but i changed server.ts to
//server.ts
export class Server{
...
}
and it worked 😎👌
Note: i am using this config
"target": "esnext",
"module": "commonjs",
I faced the same issue in a module that has no exports. I used it for side-effects only. This is what the TypeScript docs say about importing side-effects modules:
Though not recommended practice, some modules set up some global state that can be used by other modules. These modules may not have any exports, or the consumer is not interested in any of their exports. To import these modules, use:
import "./my-module.js";
In that situation, you can fix the "File is not a module" error by simply exporting an empty object:
// side-effects stuff
export default {};
I faced the same issue ("File is not a module error") for import js in vue component
import handleClientLoad from "../../../public/js/calendar.js"
I do this and solve it
// #ts-ignore
import handleClientLoad from "../../../public/js/calendar.js"
The file needs to add Component from core hence add the following import to the top
import { Component } from '#angular/core';

Categories