Use JavaScript class in TypeScript - javascript

I have a problem introducing TypeScript to our JavaScript project.
First I want to use TypeScript only in my part of the code, leaving the JavaScript untouched.
Now I try to use a JavaScript class in my TypeScript code, but I don't find a solution in the last days.
The head of my TypeScript class with import of the JavaScript:
import { BaseLogic } from "../baseLogic";
export class ClaimLogic extends BaseLogic {
...
The JavaScript class ("baseLogic.js"):
module.exports = class BaseLogic {
constructor(meta, logger) {
...
My *.d.ts file ("baseLogic.d.ts"):
export class BaseLogic {
meta: any;
log: any;
constructor(meta: any, logger: any)
}
The head of the compiled JavaScript:
const baseLogic_1 = require("../baseLogic");
class ClaimLogic extends baseLogic_1.BaseLogic {
...
As you see in the compiled JavaScript baseLogic_1.BaseLogic is used.
This results in following error:
TypeError: Class extends value undefined is not a constructor or null
With only baseLogic_1 after the extends keyword in the JavaScript file all is fine.
I have no idea about a solution and hope you can help me!

Your import suppose to be import * as BaseLogic from "../baseLogic";.
In that way you will get the Class that you put on module.exports.

The codesnipet in baseLogic.js exports the class.
module.exports = class BaseLogic {
constructor(meta, logger) {
...
}
You try to access with class ClaimLogic extends baseLogic_1.BaseLogic an object that includes the class BaseLogic
Solution
import BaseLogic from '../baseLogic'
// or: const BaseLogic = require("../baseLogic");
class ClaimLogic extends BaseLogic {
...
}

Related

Instantiate a JavaScript object in TypeScript

I tried to instantiate a javascript object in a typescript file, basically in an Angular Application but there is an error as object is not defined.
My JavaScript file:
import { EventEmitter } from 'events';
export default class Cursor extends EventEmitter {
constructor(el) {}
//some methods
}
My typescript file
First alternative :
declare var Cursor:any;
export class HomeComponent implements OnInit {
ngOnInit(): void {
const cursor = new Cursor();
console.log(cursor.emit('enter'))
}
}
=> ERROR ReferenceError: Cursor is not defined
Second alternative (importing js file)
import Cursor from '../utils/js/cursor';
export class HomeComponent implements OnInit {
ngOnInit(): void {
const cursor = new Cursor();
console.log(cursor.emit('enter'))
}
}
=> Property 'emit' does not exist on type 'Cursor'.
In that case there is an inheritance problem with class Cursor extending EventEmitter
Can someone give me an hand with that problem ?
Thanks

Imported function from js file, doesn't run in TS file

I'm trying to call a JS function inside a component in my TS file, but I'm getting an exception.
Component
import '../../../assets/js/gantt/ganttMaster.js';
export class TaskComponent implements OnInit {
constructor() {}
ngOnInit() {
var r = new GanttMaster();
}
}
Error:
Error referecences error: GanttMaster is not defined
You need to change the way you import the .js file:
import * as gantt from '../../../assets/js/gantt/ganttMaster.js';
export class TaskComponent implements OnInit {
constructor() {}
ngOnInit() {
var r = new gantt.GanttMaster();
}
}
If you want to use GanttMaster among several components, you can import the .js file in angular.json and declare a constant in app.module.ts like declare const GanttMaster: any. Then you can use it in your application.
Hope this helps.
UPDATE
Alternatively, you can import it the way you've already done, but declare the function manually before the import:
declare const GanttMaster: any;
import from '../../../assets/js/gantt/ganttMaster.js';
export class TaskComponent implements OnInit {
constructor() {}
ngOnInit() {
var r = new GanttMaster();
}
}
Ref: https://stackoverflow.com/a/37084553/1331040
In my project i load a js file from assets, something like this:
add this JavaScript file in scripts array in angular.json file like as above you have added jquery library.
"scripts": [
.....
"src/assets/js/custom.js"
]
custom.js:
function myTest() {
alert('Welcome to custom js');
}
You need declare in your component
declare const myTest: any;

Typescript does not see imported variable in generic type declaration

I'm trying to create a generic repository for every entity in the application
mongo-repository.ts
import { Document, Model, Types } from 'mongoose';
type MongooseModel<T> = Model<T & Document>;
export abstract class MongoRepository<T extends MongooseModel<T>> {
protected constructor(
protected readonly model: T,
) {}
}
user.repository.ts
import { User } from '../../../models/User';
import { MongoRepository } from '../../common/mongo/mongo-repository';
class Repository extends MongoRepository<User> {
constructor() {
super(User);
}
}
export const UserRepository = new Repository();
Actual results:
src/modules/user/repository/user.repository.ts:4:42 - error TS2304: Cannot find name 'User'.
4 class Repository extends MongoRepository<User> {
~~~~
Expected result:
Work.
However, I'm not getting this error message in super(User) but only in the generic declaration
Fixed,
Fix:
MongoRepository<T extends typeof Model>
class Repository extends MongoRepository<typeof User>

Override/extend static properties on ES7 classes in React.js

ES7 introduces the concept of static property and method definitions. Along with an ES7-capable transpiler, these can be used in React to specify validators and defaults for props, like so:
export default class ComponentOne extends React.Component {
static propTypes = {
foo: React.PropTypes.string
}
static defaultProps = {
foo: 'bar'
}
// ...
}
This is super handy, but gets tricky when subclasses come into play. For example, say the following module is added to the same codebase as ComponentOne above:
export default class ComponentTwo extends ComponentOne {
static propTypes = {
baz: React.PropTypes.number
}
static defaultProps = {
baz: 42
}
// ...
}
I'd like ComponentTwo to "inherit" the property validators and defaults of its superclass, ComponentOne. Instead, propTypes and defaultProps on ComponentTwo shadow those on ComponentOne, and React tosses out those defined on ComponentOne.
Since super is a reference to the current class's prototype, and static is supposed to reference values hung directly off the prototype, I thought this might work:
import _ from 'lodash';
export default class ComponentTwo extends ComponentOne {
static propTypes = _.merge(super.propTypes, {
baz: React.PropTypes.number
});
}
However, this generates an error, presumably from Babel: Parsing error: 'super' outside of function or class.
This works, but is not very portable:
export default class ComponentTwo extends ComponentOne {
static propTypes = Object.assign({
baz: React.PropTypes.number
}, ComponentOne.propTypes);
}
Are there any other ways to do this more cleanly/reusably?
I stumbled upon this question, and it's been almost 3 years, but who know, someone might need it. (And it's still relevant)
Given that when you extend a class it automatically inherits of its parent class, you would not need to overwrite the static propTypes property.
Given a parent class:
class Parent {
static propTypes = {
parentProp: PropTypes.string
}
}
If you don't want to add other propTypes/defaultProps, you can simply:
class Children extends Parent {
// Do not declare the propTypes, it will extends by itself.
}
console.log(Children.propTypes); // Will output an object with parentProp in it
If you want to explicitly tell that you extends Parent propTypes, or add new propTypes:
class Children extends Parent {
static propTypes = {
...Parent.propTypes, // Yes, you can spread static properties like everything else
childProp: Proptypes.number,
}
}
Small note, for this to work properly with Babel, you might need to include the transform-es2015-classes babel plugin in your plugins or preset. My .babelrc:
"presets": [
["env", {
"include": ["transform-es2015-classes"]
}],
"stage-0",
"react"
],
Hope this helps!
Curiously enough, using super works for static methods. I'd think it should work for static properties too. To me, then, it feels more natural to use the super class name directly:
export default class ComponentTwo extends ComponentOne {
static propTypes = _.merge({}, ComponentOne.propTypes, {
baz: React.PropTypes.number
});
}
But, to use super, one workaround I can think of is using a static method to initialize the property, which unfortunately would have to be called manually:
class ComponentTwo extends ComponentOne {
static _init() {
this.propTypes = _.merge({}, super.propTypes, {
baz: React.PropTypes.number
});
}
}
ComponentTwo._init();

Splitting up class definition in ES 6 / Harmony

Suppose I have a class in one big file like this:
export default class {
constructor () {}
methodA () {}
methodB () {}
methodC () {}
}
And I want to break up the class definition so that methodA, methodB, and methodC are each defined in their own separate files. Is this possible?
You should be able to, as class is supposed to just be syntax sugar for the usual prototype workflow:
import methodOne from 'methodOne'
import methodTwo from 'methodTwo'
class MyClass {
constructor() {
}
}
Object.assign(MyClass.prototype, {methodOne, methodTwo})
export default MyClass
#elclanrs gave a correct answer, but I would modify it to allow for the use of this. I also think this is more readable.
import methodOne from 'methodOne'
import methodTwo from 'methodTwo'
class MyClass {
constructor() {
this.methodOne = methodOne.bind(this)
this.methodTwo = methodTwo.bind(this)
}
}
export default MyClass
Tip: although if your class is so large that it warrants being split into multiple files, a better solution might be to split up the class into multiple classes.

Categories