How to declare a JS mixin for vue? - javascript

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

Related

How to access global mixin's methods in TypeScript Vue component?

I'm developing a Vue app using TypeScript. I created a mixin (shown in global.mixin.js below), and registered it with Vue.mixin() (shown in main.ts below).
global.mixin.js
import { mathHttp, engHttp } from '#/common/js/http'
export default {
methods: {
wechatShare(config) {
config.imgUrl = config.imgUrl
mathHttp.get('/wechat/config', {
url: encodeURIComponent(window.location.href),
}).then((data) => {
wx.config({
debug: false,
appId: data.appId,
timestamp: data.timestamp,
nonceStr: data.noncestr,
signature: data.signature,
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'],
})
})
wx.ready(() => {
wx.updateAppMessageShareData(config)
wx.updateTimelineShareData(config)
})
},
},
}
main.ts
I registered the global mixin with Vue.mixin():
import globalMixins from './mixins/global.mixin'
Vue.mixin(globalMixins)
But when I try to access the mixin method from within a Vue component, I get an error:
property wechatShare doesn't exist on type Test.vue
Test.vue
<script lang='ts'>
import { Component, Prop, Vue } from 'vue-property-decorator'
#Component({ components: { } })
export default class Test extends Vue {
created() {
this.setWeChatShare()
}
setWeChatShare() {
this.wechatShare
}
}
</script>
How can I solve this problem?
vue-property-decorator uses the same semantics for mixins from vue-class-component. Based on the example from vue-class-component docs, the mixin takes the same form as a component:
src/mixin.ts:
import Vue from 'vue'
import Component from 'vue-class-component'
#Component
export default class MyMixin extends Vue {
wechatShare(config) {
//...
}
}
Using the Mixins from vue-property-decorator (or mixins from vue-class-component), wrap your custom mixin, and extend it with your component:
src/App.vue:
import { Component, Mixins } from 'vue-property-decorator'
// OR
// import Component, { mixins } from 'vue-class-component'
import MyMixin from './mixin'
#Component
export default class App extends Mixins(MyMixin) {
mounted() {
this.wechatShare(/* ... */)
}
}
For those who want to use mixin globally and prevent importing in every component, this is what you can do.
src/mixins/mixin.ts
import { Vue, Component } from 'vue-property-decorator'
import Colors from "#/values/Colors"
import Strings from "#/values/Strings";
#Component
export default class Values extends Vue {
public test = 'Hello, hello, hello';
public colors: {} = Colors.light;
public strings: {} = Strings.pt
}
inside src/main.ts
import Values from "#/values/Values";//my Mixin
Vue.mixin(Values)
inside your src/shims-tsx.d.ts
// add the variables,functions ... inside the vue interface and then you will good to use them anywhere.
interface Vue {
colors,
strings
}

How to use the Data object in VueJS when using Decorators? "Expected 'this' to be used by class method 'data'."

Error > Expected 'this' to be used by class method 'data'.
I did find this, and thought I had it correct below:
TypeScript Unexpected token, A constructor, method, accessor or property was expected
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import { MOON_HOLDINGS_LINK, TWITTER_LINK } from '#/constants/links'
#Component
export default class HelloWorld extends Vue {
#Prop() private title!: string
data(): any {
return {
moonLink: MOON_HOLDINGS_LINK,
}
}
}
</script>
That's due to the class-methods-use-this rule of ESLint.
But data() shouldn't need to use this (only in very rare situations).
So you probably should suppress the warning for that specific method, as I believe data() meets the scenario described by ESLint as a possible exception to that rule:
For example, you might have a spec from an external library that requires you to overwrite a method as a regular function (and not as a static method) and does not use this inside the function body.
So you would use:
/*eslint class-methods-use-this: ["error", { "exceptMethods": ["data"] }] */
Example:
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import { MOON_HOLDINGS_LINK, TWITTER_LINK } from '#/constants/links'
#Component
export default class HelloWorld extends Vue {
#Prop() private title!: string
/*eslint class-methods-use-this: ["error", { "exceptMethods": ["data"] }] */
data(): any {
return {
moonLink: MOON_HOLDINGS_LINK,
}
}
}
</script>

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

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?

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");
}
}

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