Using a JS Class with static properties not working in Vue - javascript

I created a class with a static property in a seperate file in a Vue2 App:
export class TestUnit {
static testVar = "test";
}
When I try to import the class
import { TestUnit } from "../../poco/classes/TestUnit";
I get the "Failed to compile" - Error with the following message:
Module parse failed: Unexpected token (2:16)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| export class TestUnit {
> static testVar = "test";
I didn't find a solution searching after the error message. Do you have an idea what the problem is?
Update: Static methods in the TestUnit class are working: static test() { return "test" }; That confuses me.

You have to check your node version,
the static class fields are supported in version 12.4.0 and above.
the static methods are supported since 5.12
you can check node's supported features here: https://node.green

Related

0x800a1391 - JavaScript runtime error: 'module' is not defined

I am from a C++ background and have a day's experience in TypeScript. I am trying to implement a design (interface/class) that is split between multiple files. It is flashing runtime error : 0x800a1391 - JavaScript runtime error: 'module' is not defined
Info.ts
export = Test; <----------- 0x800a1391 - JavaScript runtime error: 'module' is not defined
namespace Test {
export class Info {
}
}
TestWrapper.ts
import { Info } from "./Info";
namespace Test {
class TestWrapper {
public GetInfo(): Info {
return this.m_info;
}
}
}
Am I using something in the wrong way?
A guess:
export = Something
Compiles to something like
module.exports = Something
module.exports is a construct of the so-called "commonjs module system", something that is not available in browsers, but in node.js. So if you run the generated code in a browser through a direct <script> import, it will bring an error like that. TS transpiles imports and exports to module systems that can be specified in the tsconfig.json, but TS itself is not responsible for implementing the module system.
What to do?
If this code is really supposed to run in the browser, you could opt on one of the 2 following options:
Run the code through a module bundler (webpack), which will generate a browser compatible "bundle" (a big JS) concatenating all your files. Webpack has ways of including typescript as a plugin, so that you dont need to make your "build" a 2-step process; Module bundlers are usually fairly complicated.
Make your files module-less (which means: no top-levem imports or exports) and import them through vanilla <script> tags.
Am I using something in the wrong way?
While namespaces are commonly used in other languages, they do not exist in JavaScript, so the typescript version is just some rarely used way to add proper typing to some things (I never used it yet). In your case you actually don't need a namespace. Just:
export default class Info { /*...*/ }
Then you can
import Info from ".Info";
export default class TestWrapper { /*...*/ }
PS: That said, I actually don't know how to make this work with namespaces to resolve the error
It looks like you are trying to mix modules and namespaces. I would suggest reading Namespaces and Modules.
You don't need to to export at the top level using export = Test, you also shouldn't import { Info } from "./Info"; because Info is part of the Test namespace which TestWrapper is a member of.
If you want to go the namespace route, consider:
Info.ts
namespace Test {
export class Info {}
}
TestWrapper.ts
namespace Test {
export class TestWrapper {
m_info: Info;
public GetInfo(): Info {
return this.m_info;
}
}
}
Consumer.ts
console.log(Test.TestWrapper);
Compile this using:
tsc --outFile foo.js Info.ts TestWrapper.ts Consumer.ts
Then run using:
node foo.js
Which prints:
[Function: TestWrapper]

Extend typescript definitelyTyped definition file

I'm getting the following error:
src/models/priceAdjustment.ts(55,2): error TS2345: Argument of type '{ as: string; foreignKey: string; gql: any; }' is not assignable to parameter of type 'AssociationOptionsHasMany'.
Object literal may only specify known properties, and 'gql' does not exist in type 'AssociationOptionsHasMany'.
The error is obvious, I'm trying to assign a "gql" key which doesn't exist (I'm attaching it on so I can access it later on in my code somewhere else).
What I'd like to do, is extend the model.hasMany interface here, and add my own key. Is this possible? If so, how do I?
My current workaround is to cast the object to <any> before passing it in, which feels like a dirty workaround.
I have attempted the following:
import Sequelize from 'sequelize';
export declare module Sequelize {
export interface MyAssociationOptionsHasMany extends Sequelize.AssociationOptionsHasMany {
gql?: any
}
export interface MyAssociations extends Sequelize.Associations {
hasMany(target: Sequelize.Model<any, any>, options?: MyAssociationOptionsHasMany): void;
}
}
And now I get the following error:
TypeError: Cannot read property '239' of undefined
at getDeclarationSpaces (C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:33121:54)
at checkExportsOnMergedDeclarations (C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:33067:41)
at checkModuleDeclaration (C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:35036:17)
at checkSourceElement (C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:35505:28)
at Object.forEach (C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:275:30)
at checkSourceFileWorker (C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:35566:20)
at checkSourceFile (C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:35551:13)
at getDiagnosticsWorker (C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:35604:17)
at Object.getDiagnostics (C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:35593:24)
at C:\Users\user\AppData\Roaming\npm\node_modules\typescript\lib\tsc.js:56188:85
You can do this via Declaration Merging. The best way I have found this to work is by importing the library into an "extension" file and extending the library from there. For instance,
extensions/library-name.extension.ts:
import AssociationOptionsHasMany from '/path/to/definition';
import 'library-name';
declare module 'library-name' {
interface InterfaceToExtend {
hasMany(options: AssociationOptionsHasMany): ReturnType;
}
}
In the above example, we want to extend an Interface created in the library-name module. Since we are using imports, TypeScript automatically creates a module for the file, so we have to tell TypeScript that we want to extend the interface in the library-name module, not the module created for this file. To do that, we simply declare the module using the same name as the library we imported.
After telling TypeScript in which module the interface should be extended, we just use Declaration Merging by defining an interface with the same name as the interface that should be extended and adding whatever we need to it. In this case, that would be a new method that takes as an argument the specific type we want to pass it.
I have also had to update the tsconfig.json file so the extensions would be loaded first. You can do that by including the extensions directory before the rest of the app:
{
/* Blah, settings, blah */
includes: ['./app/extensions/*.ts', './app/**/*.ts'],
/* Blah, settings, blah */
}
If you're using Sublime, it might complain still, but actually compiling the code or exiting out of Sublime and reopening it seems to work just fine.
A word of warning. Declaration Merging is powerful, but can result in unexpected behavior. In general, try to avoid extending components you (or someone else) have defined elsewhere. If may be a sign that you are using these components incorrectly or the need for refactoring. Remember, the benefit of TypeScript is strict(er) typing.

Class has or is using name 'SafeUrl' from external module but cannot be named

I'm using sanitizer.bypassSecurityTrustUrl to put links to blobURL's on the page. This works just fine as long as I don't AoT compile the project.
import {DomSanitizer} from '#angular/platform-browser';
export class AppComponent {
constructor(private sanitizer: DomSanitizer) {
}
sanitize(url: string) {
return this.sanitizer.bypassSecurityTrustUrl(url);
}
}
The sanitize function takes a URL like this:
blob:http://localhost:4200/7c1d7221-aa0e-4d98-803d-b9be6400865b
If I use AoT compilation I get this error message:
Module build failed: Error: /.../src/app/app.component.ts (18,3):
Return type of public method from exported class has or is using name
'SafeUrl' from external module
"/.../node_modules/#angular/platform-browser/src/security/dom_sanitization_service"
but cannot be named.)
I'm using CLI with Angular 2.1.0
Anybody knows how I can circumvent this problem? Or should it be reported as a bug?
So it seems I had to add a return type of SafeUrl to the method
sanitize(url: string):SafeUrl {
return this.sanitizer.bypassSecurityTrustUrl(url);
}
Big thanks to alxhub
In my case i was initiating an attribute like this :
public img64 = this.domSanitizer.bypassSecurityTrustResourceUrl('data:image/jpg;base64,' + this.base64Image);
Resulting in the same error.
Thanks to #mottosson I got it right (just add the type SafeUrl):
public img64: SafeUrl = this.domSanitizer.bypassSecurityTrustResourceUrl('data:image/jpg;base64,' + this.base64Image);

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';

TypeScript: access global var from a class without import

I got this module like this:
module MyModule {
export class Constants {
public static WIDTH:number = 100;
public static HEIGHT:number = 100;
....
}
}
export = MyModule;
Now I need to use MyModule.Constants.WIDTH in another class but I can't use import (I need to deliver this class js to a third party, and they don't use requirejs). Right now I use reference to get code checking but it keep giving this error (at transpilling time)
error TS2095: Could not find symbol 'MyModule'
What should I do now so I can use autocomplete and get rid of this error?
I hope you're not mindplay on the TypeScript forum otherwise I'm about to repeat myself.
export and import work together. You should either be using both or neither. If you check what the generated code looks like with and without the export keyword you'll see that export causes a module to be built. Since the third party can't use RequireJS I don't think this is what you want.
I would structure my classes like the following:
// file pkg/Foo.ts
module company.pkg {
export class Foo {}
}
// file pkg2/Bar.ts
module company.pkg2 {
export class Bar{}
}
Putting everything into the name space of your company minimizes the chance of a conflict with another library. Classes know about each other using a reference /// <reference path="..." /> which will allow it to compile.
Since you're not doing modules I would also compile to a single file using --out filename.js. That gets all the files included in (usually) the right order.

Categories