how to convert to import/export module's syntax by TypeScript global module - javascript

I want to convert older project's typescript code, for example:
// dataService.ts
module ProjectNs.Models {
export class DataService {
props1: string;
constructor(
private service: ProjectNs.Service.MyInjectService
) { }
}
}
it's equal global variable's method. now, I want to use webpack, and like es6 module syntax. for example:
// dataService.ts
export class DataService {
props1: string;
constructor(
private service: ProjectNs.Service.MyInjectService
) { }
}
// main.ts
import {DataService} from './dataService';
class Main {
}
There are so many TypeScript File, so, Is there any tool for batch conversion?

Related

Inject correct service based on parameter

Let's assume I have a two modules which are exporting BService and CService where both of those services extends AService
So code looks like this:
abstract class AService {
public run() {}
}
#Injectable()
export class BService extends AService {}
#Injectable()
export class CService extends AService {}
#Module({
providers: [BService],
exports: [BService],
})
export class BModule {}
#Module({
providers: [CService],
exports: [CService],
})
export class CModule {}
#Injectable()
class AppService {
constructor(protected readonly service: AService) {}
public run(context: string) { // let's assume context may be B or C
this.service.run();
}
}
#Module({
imports: [CModule, BModule],
providers: [{
provide: AppService,
useFactory: () => {
return new AppService(); // how to use BService/CService depending on the context?
}
}]
})
export class AppModule {}
But the key is, I cannot use REQUEST (to inject it directly in useFactory) from #nestjs/core as I'm using this service in cron jobs and with the API call
I also don't think Factory pattern is useful there, I mean it would work but I want to do it correctly
I was thinking about property based injection.
But I'm not sure how to use it in my case
In my opinion, the factory approach is exactly what you need. You described that you need a different service based on the context which is a great for for the factory approach. Let's try this:
Create an injectable factory:
import { Injectable } from '#nestjs/common';
import { AService } from './AService';
import { BService } from './BService';
import { CService } from './CService';
#Injectable()
export class ServiceFactory {
public getService(context: string) : AService {
switch(context) {
case 'a': return new BService();
case 'b': return new CService();
default: throw new Error(`No service defined for the context: "${context}"`);
}
}
}
Now import that factory into your app module:
import { ServiceFactory } from './ServiceFactory';
import { AService } from './AService';
#Module({
providers: [AppService, ServiceFactory]
})
export class AppModule {}
Now your app service will get the factory as a dependency which will create the appropriate service based on the context:
import { ServiceFactory } from './ServiceFactory';
import { AService } from './AService';
#Injectable()
class AppService {
constructor(readonly serviceFactory: ServiceFactory) { }
public run(context: string) {
const service: AService = this.serviceFactory.getService(context);
service.run();
}
}
If the property is static (e.g. environment variable), you can use a custom provider to choose the proper instance. However, if the property is in someway dynamic, you cannot soley rely on nest's dependency injection as it instantiates the provider on startup (with the exception of REQUEST scope, which isn't an option for you).
Static Property
Create a custom provider that instantiates the needed implementation based on a static property (e.g. environment variable).
{
provide: AService,
useClass: process.ENV.useBService ? BService : CService,
}
Dynamic Property with Request-Scope
Let's assume we have two different implementations of a service:
#Injectable()
export class BService {
public count = 0;
run() {
this.count++;
return 'B';
}
}
#Injectable()
export class CService {
public count = 0;
run() {
this.count++;
return 'C';
}
}
When the sum of the count variables of both is even, the BService should be used; CService when it's odd. For this, we create a custom provider with request scope.
{
provide: 'MyService',
scope: Scope.REQUEST,
useFactory: (bService: BService, cService: CService) => {
if ((bService.count + cService.count) % 2 === 0) {
return bService;
} else {
return cService;
}
},
inject: [BService, CService],
},
If our controller now injects the MyService token (#Inject('MyService')) and exposes its run method via an endpoint it will return B C B ...
Dynamic Property with Default-Scope
As we want to use the default scope (Singleton!), the static instantiation of nest's dependency injection cannot be used. Instead you can use the delegate pattern to select the wanted instance in the root class (AService in your example).
Provide all services as they are:
providers: [AService, BService, CService]
Decide dynamically in your AService which implementation to use:
#Injectable()
export class AService {
constructor(private bService: BService, private cService: CService) {}
run(dynamicProperty) {
if (dynamicProperty === 'BService') {
return this.bService.run();
} else {
return this.cService.run();
}
}
}

How to declare a JS mixin for vue?

I'm writting a vue project with typescript and I want to use a mixin from thrid-part library which write by javascript, how to write a .d.ts to make ts can find function define in the mixin?
I tried this way and it not working:
// common.d.ts
declare module 'thrid-part-lib' {
import { VueClass } from 'vue-class-component/lib/declarations';
export interface SomeMixin<T> extends VueClass<T> {
refresh(): Promise<void>;
}
}
// index.ts
import { Component, Mixins } from 'vue-property-decorator';
import { SomeMixin } from 'thrid-part-lib';
#Component
export default class Index extends Mixins(SomeMixin) {
public foo() {
this.refresh(); // 'refresh' is not define.
}
}
You can augment a third party mixin with creating a file like vuelidate-error-extractor.d.ts:
declare module 'vuelidate-error-extractor' {
import { ValidationRule } from 'vuelidate/lib/validators';
// eslint-disable-next-line #typescript-eslint/class-name-casing
export class singleErrorExtractorMixin extends Vue {
readonly events: any;
readonly name: string;
readonly isValid: boolean;
readonly hasErrors: boolean;
readonly preferredValidator: ValidationRule;
}
}
This augments this JS file, but in an incomplete manner.
This is documented in "Augmenting Types for Use with Plugins".
Put this in a .d.ts file in your project to add a refresh() mixin method to components:
// 1. Make sure to import 'vue' before declaring augmented types
import Vue from 'vue'
// 2. Specify a file with the types you want to augment
// Vue has the constructor type in types/vue.d.ts
declare module 'vue/types/vue' {
// 3. Declare augmentation for Vue
interface Vue {
refresh(): void;
}
}

How to call classes and function in type definition file?

I'm newbe in typescript and trying to use type definition file with typescript 2.2, (I'm using typescriptlang.org but can't get answer)I have the following type definition file
export as namespace mydefinition;
export namespace mynamespace {
interface Myinterface {
width: number;
height: number;
}
class MyClass {
constructor(attributes?: any);
addCell(cell: Cell): this;
}
}
I'm using the following line to import file and it success
import { mydefinition } from 'definitionfile';
How can I call the classes and function of this definition file?
Looks good to me. You are just missing the initialization of your myclass.
import { mydefinition } from './definitionfile';
export class classA implements mydefinition.Myinterface {
width: number;
height: number;
constructor() {
var test = new mydefinition.MyClass();
test.addCell("attr");
}
}

Getting error can not compile module unless --module flag is provided. so not able to create instance of this class in another ts file

export module FilterBar {
export class Filter {
objData: any;
distinctAreas: string[];
distinctRegions: string[];
distinctSubRegions: string[];
distinctAreasApplied: string[];
distinctRegionsApplied: string[];
distinctSubRegionsApplied: string[];
call = 0;
static selectedFilterData: any;
}
I want to create an object of this class in another typescript file. For that I am using export to module but I am getting the mentioned error.

Typescript - internal module cannot be imported - unexpected behavior

I have 2 modules spread across 2 files as such:
--App.Tools.Utils.ts
export interface ILogger {
log: (msg: string) => void;
}
module App.Tools.Utils {
export class Logger implements ILogger { ... }
export function someFunction(){ ... }
}
then in the second file I import the module:
--App.Routers.ts
/// <reference path="App.Tools.Utils.ts" />
module App.Routers {
import Utils = App.Tools.Utils; //ERROR: A module cannot be aliased to a non-module type
}
I eventually figured out the solution was to move the ILogger interface INSIDE the App.Tools.Utils module to resolve the error. At first it made some sense, I figured the compiler wouldn't let me import the module because the Logger class implemented an interface that was not included in the module. To test, I moved the ILogger interface inside the module (error resolved) but then added an arbitrary interface right outside the module (one that is not used inside the module or anywhere) and the error returns..
export interface INeverUsed { } //generates same error
module App.Tools.Utils {
export interface ILogger {
log: (msg: string) => void;
}
export class Logger implements ILogger { ... }
export function someFunction(){ ... }
}
Looking at the generated JS, adding the interface outside the module generates a define(["require", "exports"] wrapper and that results in the error when trying to import the App.Tools.Utils module in the other file. Removing the interface removes the define wrapper and the resolves the error.
Is it behavior expected? It makes no sense to me why a module is suddenly "closed" when I define an interface in the same file but outside the module, especially if that interface is not even used inside the module.
Because you are using the export keyword on the interface, the compiler is treating the file as a module.
If you remove the export keyword on the interface, it should work:
interface ILogger {
log: (msg: string) => void;
}
module App.Tools.Utils {
export class Logger implements ILogger {
log(msg: string) { }
}
export function someFunction(){ }
}
And
///<reference path="game.ts" />
module App.Routers {
import Utils = App.Tools.Utils; // works
}

Categories

Resources