preface
Actually,Vue
The official fromX 2.6.
Version begins with partial useTs
Rewritten.
Personally, I don’t have a positive view on stricter type restrictions, after all, all kinds of conversion of the style of writing habit.
One of my most recent projects is TypeScript+ Vue. … How sweet!
Note the “before” of the title of this article. This article is intended to cover the use of Ts blending frameworks, not the Class API
1. Build using official scaffolding
npm install -g @vue/cli
# OR
yarn global add @vue/cli
Copy the code
The new Vue CLI tool allows developers to create new projects using the TypeScript integrated environment.
Just run vue create my-app.
The command line then asks you to select the default. Use the arrow keys to select Manually Select Features.
Next, just make sure the TypeScript and Babel options are selected, as shown below:
When you’re done, it asks you if you want to use classstyle Component syntax.
Then configure the rest of the Settings to look like the figure below.
The Vue CLI tool will now install all dependencies and set up the project.
Anyway, start running.
2. Parse the project directory
When you look at the directory structure with the tree directive, you can see that the structure is quite different from what you would normally build.
The main focus here is on the shims-tsX.d. ts and shims-vue.d.ts files
In two sentences:
shims-tsx.d.ts
You are allowed to.tsx
At the end of the fileVue
Write in a projectjsx
codeshims-vue.d.ts
It is mainly used forTypeScript
identify.vue
File,Ts
Import is not supported by defaultvue
The file, the file tellsts
The import.vue
Files are according to theVueConstructor<Vue>
To deal with.
At the moment we open the kind of SRC/components/HelloWorld vue, will find that writing is different
<template>
<div class="hello"> <h1>{{ msg }}</h1> <! </div> </template> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
exportdefault class HelloWorld extends Vue { @Prop() private msg! : string; } </script> <! -- Add"scoped" attribute to limit CSS to this component only -->
<style scoped></style>
Copy the code
At this point, we’re ready to open a new chapter: TypeScript Speedup and Vue-Property-Decorator
3. TypeScript
Introduction to speed
3.1 Basic types and extension types
Typescript shares the same basic types as Javascript, but there are a few additional types.
- tuples
Tuple
- The enumeration
enum
Any
与Void
1. Collection of basic types
// Numbers are supported, including two, eight, and hexadecimallet decLiteral: number = 6;
lethexLiteral: number = 0xf00d; // This is a stringlet name: string = "bob";
let sentence: string = `Hello, my name is ${ name }. // Array. The second way is to use the Array generic, Array< element type > :let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
let u: undefined = undefined;
let n: null = null;
Copy the code
2. Special types
1. tuplesTuple
Thinking of tuples as organized arrays, you need to pre-define the data types in the right order.
const messyArray = [' something'.2.true.undefined.null];
const tuple: [number, string, string] = [24."Indrek" , "Lasn"]
Copy the code
Typescript warns you if you don’t follow the indexing rules that sort tuples by default.
(The first item of a tuple should be of type number)
2. The enumerationenum
The enum type is a complement to the JavaScript standard data type. As in other languages such as C#, enumeration types are used to give friendly names to sets of values.
Enum Color {Red = 1, Green = 2, Blue = 4} enum Color {Red = 1, Green = 2, Blue = 4}let c: Color = Color.Green;
letcolorName: string = Color[2]; console.log(colorName); / / output'Green'Because in the code above it has a value of 2Copy the code
Another good example is the use of enumerations to store application state.
3. Void
In Typescript, you must define return types in functions. Like this:
If no value is returned, an error is reported:
We can define the return value as void:
There will be no return at this point
4. Any
Emmm… It just doesn’t matter what type you’re dealing with, you can use this when you’re not sure what type you’re dealing with.
But use it carefully, too much will lose the meaning of using Ts.
let person: any = "Front end troubleshooter"
person = 25
person = true
Copy the code
The application scenarios are as follows:
- Accessing a third-party library
- Ts vegetable force is used in the early stage
5. Never
To put it mildly: “Never is the father you will Never have.”
The specific actions are:
throw new Error(message)
return error("Something failed")
While (true) {} // There is an endpoint that cannot be reached
3. Type assertion
The shorthand definition is that it can be used to manually specify the type of a value.
There are two ways to write it, Angle brackets and as:
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
let strLength: number = (someValue as string).length;
Copy the code
Examples are:
When TypeScript does not determine what type a variable of a union type is, we can only access properties or methods that are common to all types of the union type:
function getLength(something: string | number): number {
return something.length;
}
// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.
Copy the code
An error will be reported if you access the length, and sometimes, we do need to access a property or method of one of the types before we know what type it is, so we need an assertion to avoid an error:
function getLength(something: string | number): number {
if ((<string>something).length) {
return (<string>something).length;
} else {
returnsomething.toString().length; }}Copy the code
3.2 generics:Generics
A major part of software engineering is building components that are not only clearly defined and have uniform interfaces, but are also reusable. Components that support existing data types and future additions provide great flexibility in the development process for large software systems.
In C# and Java, you can use “generics” to create reusable components that support multiple data types. This allows users to use components based on their data types.
1. Generic methods
In TypeScript, there are two ways to declare generic methods:
function gen_func1<T>(arg: T): T {
returnarg; } / / orlet gen_func2: <T>(arg: T) => T = function (arg) {
return arg;
}
Copy the code
There are also two methods of calling:
gen_func1<string>('Hello world');
gen_func2('Hello world'); // In the second call, the type parameter can be omitted, because the compiler will automatically identify the corresponding type based on the parameters passed.Copy the code
2. The generic andAny
The “Any” special type of Ts can be used in place of Any type. At first sight, there is no difference between the two types.
// Method 1: the method with any parameterfunction any_func(arg: any): any {
console.log(arg.length);
returnarg; } // Array generic methodfunction array_func<T>(arg: Array<T>): Array<T> {
console.log(arg.length);
return arg;
}
Copy the code
- Method number one, it’s printed
arg
Parameters of thelength
Properties. becauseany
Can be substituted for any type, so the method is passed either an array or withlength
Property object, an exception is thrown. - Method two defines the parameter type is
Array
For generic types, there must belength
Property, so no exception will be thrown.
3. Generic types
Generic interfaces:
interface Generics_interface<T> {
(arg: T): T;
}
function func_demo<T>(arg: T): T {
return arg;
}
letfunc1: Generics_interface<number> = func_demo; func1(123); // The actual parameter func1 of the correct type ('123'); // The actual parameter of the error typeCopy the code
3.3 User-defined Types:Interface
vs Type alias
Interface.
Type alias.
The following is from:
What’s the difference between interface and type in Typescript
1. The similarities
Can be used to describe an object or function:
interface User {
name: string
age: number
}
type User = {
name: string
age: number
};
interface SetUser {
(name: string, age: number): void;
}
type SetUser = (name: string, age: number): void;
Copy the code
Both allow an extension (extends) :
Both interface and Type can be extended, and they are not independent of each other, which means interface extends Type and type extends Interface. The effect is similar, but the syntax is different.
interface extends interface
interface Name {
name: string;
}
interface User extends Name {
age: number;
}
Copy the code
type extends type
type Name = {
name: string;
}
type User = Name & { age: number };
Copy the code
interface extends type
type Name = {
name: string;
}
interface User extends Name {
age: number;
}
Copy the code
type extends interface
interface Name {
name: string;
}
type User = Name & {
age: number;
}
Copy the code
2. The difference between
type
Can theinterface
no
type
You can declare basic type aliases, union types, tuples, and so on
// Basic type aliasestypeName = string // union type interface Dog {wong(); } interface Cat { miao(); }typePet Dog = | Cat / / specific definition array type of each positiontype PetList = [Dog, Pet]
Copy the code
type
Statement can also be usedtypeof
Gets the type of the instance for assignment
// use typeof when you want to get the typeof a variablelet div = document.createElement('div');
type B = typeof div
Copy the code
- Other SAO operation
type StringOrNumber = string | number;
type Text = string | { text: string };
type NameLookup = Dictionary<string, Person>;
type Callback<T> = (data: T) => void;
type Pair<T> = [T, T];
type Coordinates = Pair<number>;
type Tree<T> = T | { left: Tree<T>, right: Tree<T> };
Copy the code
interface
Can thetype
no
Interfaces can declare merges
Interface User {name: string age: number} interface User {sex: string} /* User Interface: {name: string age: number sex: string } */Copy the code
Interface has optional properties and read-only properties
-
Optional attribute
Not all properties in an interface are required. Some exist only under certain conditions, or not at all. For example, if only some properties are assigned to the parameter object passed to a function. An interface with optional attributes is similar to a normal interface definition, except that the optional attribute name definition is followed by a? Symbols. As shown below.
interface Person { name: string; age? : number; gender? : number; }Copy the code
-
Read-only property
As the name implies, this property is not writable, and the object property can only change its value when the object is newly created. You can specify a read-only property by using readonly before the property name, as shown below:
interface User {
readonly loginName: string;
password: string;
}
Copy the code
As the above example shows, loginName cannot be changed after the User object is initialized.
3.4 Implementation and Inheritance:implements
vsextends
Extends is obviously an ES6 class inheritance, so what does implement do? How is it different from extends?
Implement. Similar to the basic use of interfaces in C# or Java, TypeScript can use them to explicitly force a class to conform to a contract
Implement basic usage:
interface IDeveloper { name: string; age? : number; } // OK class dev implements IDeveloper { name ='Alex';
age = 20;
}
// OK
class dev2 implements IDeveloper {
name = 'Alex';
}
// Error
class dev3 implements IDeveloper {
name = 'Alex';
age = '9';
}
Copy the code
Extends extends is the parent of an inheritance class, so you can use both of them in a mixed way:
class A extends B implements C,D,E
Copy the code
With interface and type:
3.5 Declaration files and Namespaces:declare
和 namespace
Before we talked about shims-tsX.D. ts and Shims-vue.D. ts in project Vue, the initial content of which looks like this:
// shims-tsx.d.ts
import Vue, { VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
// shims-vue.d.ts
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
Copy the code
Declare: When using a third-party library, we need to reference its declaration file to get code completion, interface hints, and other functions.
Here are a few common ones:
declareVar declares global variablesdeclare functionDeclaring global methodsdeclareClass Declares a global classdeclareEnum Specifies a global enumeration typedeclareGlobal Extends global variablesdeclareModule Extension moduleCopy the code
Namespace: “internal module” is now called “namespace”
Module X {equivalent to the now recommended namespace X {)
Collaborate with other JS libraries
It is also possible to create a.d.ts file declaration file for other JS libraries that use the namespace. For example, for D3 JS libraries, you can create such a declaration file:
declare namespace D3{
exportinterface Selectors { ... }}declare var d3: D3.Base;
Copy the code
So the above two files:
shims-tsx.d.ts
, in the global variableglobal
Several internal modules are batch named inshims-vue.d.ts
“Means to tellTypeScript
*.vue
Suffixed files can be handed invue
Module to handle.
3.6 Access modifier:private
,public
,protected
It makes sense:
-
The default for the public
-
When a member is marked private, it cannot be accessed outside the class that declared it. For example:
class Animal { private name: string; constructor(theName: string) { this.name = theName; }}let a = new Animal('Cat').name; // Error, 'name' is privateCopy the code
protected
andprivate
Similar, but,protected
Members are accessible in derived classes
class Animal {
protected name: string;
constructor(theName: string) {
this.name = theName;
}
}
class Rhino extends Animal {
constructor() {
super('Rhino');
}
getName() {console.log(this.name)}}Copy the code
3.7 Optional parameters (? 🙂 and the non-empty assertion operators (! .).
Optional parameters
functionbuildName(firstName: string, lastName? : string) {return firstName + ' '+ lastName} // Error demo buildName("firstName"."lastName"."lastName") // Demonstrate buildName correctly ("firstName") // Demonstrate buildName correctly ("firstName"."lastName")
Copy the code
Non-empty assertion operators:
Used when you can be sure that the variable value is not null.
Unlike optional arguments, non-empty assertion operators do not prevent null or undefined.
lets = e! .name; // Assert e is non-null and access the name attributeCopy the code
4. Vue
The component’sTs
writing
Vue has better support for TS since Vue 2.5. According to the official documentation, vue can be written in typescript in two ways:
**Vue.extend **
import Vue from 'vue'
const Component = Vue.extend({
// type inference enabled
})
Copy the code
vue-class-component
import { Component, Vue, Prop } from 'vue-property-decorator'
@Component
export default class Test extends Vue {
@Prop({ type: Object })
private test: { value: string }
}
Copy the code
Ideally, vue. extend is the cheapest way to learn. On the basis of the existing writing method, almost zero cost of migration.
The vue. extend pattern, however, needs to be used in conjunction with mixins. Methods defined in mixins are not recognized by typescript
This means missing code hints, type checking, compile errors, and so on.
The rookies choose. The big boys choose the best. Let’s move on to the second one:
4.1 vue-class-component
We went back to SRC/components/HelloWorld. Vue
<template>
<div class="hello"> <h1>{{ msg }}</h1> <! </div> </template> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
exportdefault class HelloWorld extends Vue { @Prop() private msg! : string; } </script> <! -- Add"scoped" attribute to limit CSS to this component only -->
<style scoped></style>
Copy the code
For those of you who have written Python, this sounds familiar:
vue-property-decorator
This officially supported library provides function decorators (modifiers) syntax
1. Function modifiers@
“@” is not so much a modifier as a reference to or call to the function it decorates.
Or in plain English: @: “I’m surrounded by the following.”
For example, the following code contains two functions that have not been called, but will produce output:
test(f){ console.log("before ..." ); f() console.log("after ..." ); } @test func(){ console.log("func was called"); }Copy the code
Run directly, output results:
before ...
func was called
after ...
Copy the code
The above code can be seen:
- Only two functions are defined:
test
andfunc
They are not called. - If there is no “@test”, the run should have no output.
However, when the interpreter reads the function modifier “@”, the following steps look like this:
-
To call test, the entry argument to test is the function called “func”;
-
The test function is executed, and the entry argument (i.e. Func) is called (executed);
In other words, the entry argument of the function with the modifier is the entire function below. Function a (function () {… });
2. vue-property-decorator
andvuex-class
Decorator provided
Vue-property-decorator:
@Prop
@PropSync
@Provide
@Model
@Watch
@Inject
@Provide
@Emit
@Component
(provided by vue-class-component)Mixins
(the helper function namedmixins
provided by vue-class-component)
Vuex-class decorator:
- @State
- @Getter
- @Action
- @Mutation
Let’s look at the original Vue component template:
import {componentA,componentB} from '@/components';
export default {
components: { componentA, componentB},
props: {
propA: { type: Number },
propB: { default: 'default value' },
propC: { type: [String, Boolean]},} // Component datadata () {
return {
message: 'Hello'}}, // computed: {reversedMessage () {
return this.message.split(' ').reverse().join(' '} // Vuex datastep() {
return this.$store.state.count
}
},
methods: {
changeMessage () {
this.message = "Good bye"
},
getName() {
let name = this.$store.getters['person/name']
returnName}}, // Life cyclecreated() {},mounted() {},updated() {},destroyed() {}}Copy the code
}}}}}}}}}}}}}}
import { Component, Vue, Prop } from 'vue-property-decorator';
import { State, Getter } from 'vuex-class';
import { count, name } from '@/person'
import { componentA, componentB } from '@/components';
@Component({
components:{ componentA, componentB},
})
export default class HelloWorld extends Vue{
@Prop(Number) readonlypropA! : number | undefined @Prop({ default:'default value' }) readonlypropB! : string @Prop([String, Boolean])readonlypropC! : string | Boolean | undefined / / the original data message ='Hello'Private get reversedMessage (): string[] {return this.message.split(' ').reverse().join(' '} @state ((State: IRootState) => state.booking.currentstep) step! : number @Getter('person/name') name! : name // method public changeMessage (): void { this.message ='Good bye'
},
public getName(): string {
let storeName = name
returnStoreName} private created () : void {}, private Mounted () : void {}, private updated () : Void {}, private destroyed () : void {}}Copy the code
As you can see, we added the private XXXX method to the lifecycle list as this should not be exposed to other components.
The reason for not making method private is that @Emit might be used to pass messages to the parent component.
4.2 Adding global Tools
To import global modules, change main.ts:
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
Vue.config.productionTip = false;
new Vue({
router,
store,
render: (h) => h(App),
}).$mount('#app');
Copy the code
npm i VueI18n
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store'; // New module import i18n from'./i18n';
Vue.config.productionTip = false; New Vue({router, store, i18n, // new module render: (h) => h(App),}).$mount('#app');
Copy the code
But that alone is not enough. You need to move SRC /vue-shim.d.ts:
// Declare global methodsdeclare module 'vue/types/vue' {
interface Vue {
readonly $i18n: VueI18Next;
$t: TranslationFunction; }}Copy the code
If you use this.$i18n(), no error will be reported.
4.3 Axios usage and encapsulation
Axios encapsulates thousands of faces
If you want to simply experience using Axios in Ts, you can install Vue-Axios and use Axios simply
$ npm i axios vue-axios
Copy the code
The main. Ts to add:
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
Copy the code
Then use it within a component:
Vue.axios.get(api).then((response) => {
console.log(response.data)
})
this.axios.get(api).then((response) => {
console.log(response.data)
})
this.$http.get(api).then((response) => {
console.log(response.data)
})
Copy the code
1. Create a filerequest.ts
File directory:
-api -main. ts // Actual call -utils-request. ts // Interface encapsulationCopy the code
2. request.ts
File parsing
import * as axios from 'axios';
import store from '@/store'; // Replace import {Toast} from depending on the UI component library used'vant';
import { AxiosResponse, AxiosRequestConfig } from 'axios'; Const baseURL = process.env.vue_app_URL; /* const baseURL = process.env.vue_app_URL; /* Create axios instance */ const service = axios.default.create({baseURL, timeout: 0, // maxContentLength: 4000,}); service.interceptors.request.use((config: AxiosRequestConfig) => {return config;
}, (error: any) => {
Promise.reject(error);
});
service.interceptors.response.use(
(response: AxiosResponse) => {
if(response.status ! == 200) { Toast.fail('Request error! ');
} else {
return response.data;
}
},
(error: any) => {
return Promise.reject(error);
});
export default service;
Copy the code
To make things easier, we also need to define a fixed set of formats that Axios returns by creating ajax.ts:
export interface AjaxResponse {
code: number;
data: any;
message: string;
}
Copy the code
3. main.ts
Interface call:
// api/main.ts
import request from '.. /utils/request';
// get
export function getSomeThings(params:any) {
return request({
url: '/api/getSomethings'}); } // postexport function postSomeThings(params:any) {
return request({
url: '/api/postSomethings',
methods: 'post',
data: params
});
}
Copy the code
5. Write a component
In order to reduce the time, we can replace the SRC/components/HelloWorld vue, do a blog post components:
<template>
<div class="blogpost">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
<p class="meta">Written by {{ post.author }} on {{ date }}</p>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'; // This is where the data is typedexport interface Post {
title: string;
body: string;
author: string;
datePosted: Date;
}
@Component
exportdefault class HelloWorld extends Vue { @Prop() private post! : Post; getdate() {
return `${this.post.datePosted.getDate()}/${this.post.datePosted.getMonth()}/${this.post.datePosted.getFullYear()}`;
}
}
</script>
<style scoped>
h2 {
text-decoration: underline;
}
p.meta {
font-style: italic;
}
</style>
Copy the code
Then use it in home.vue:
<template>
<div class="home">
<img alt="Vue logo" src=".. /assets/logo.png">
<HelloWorld v-for="blogPost in blogPosts" :post="blogPost" :key="blogPost.title" />
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld, { Post } from '@/components/HelloWorld.vue'; // @ is an alias to /src
@Component({
components: {
HelloWorld,
},
})
export default class Home extends Vue {
private blogPosts: Post[] = [
{
title: 'My first blogpost ever! ',
body: 'Lorem ipsum dolor sit amet.',
author: 'Elke',
datePosted: new Date(2019, 1, 18),
},
{
title: 'Look I am blogging! ',
body: 'Hurray for me, this is my second post! ',
author: 'Elke',
datePosted: new Date(2019, 1, 19),
},
{
title: 'Another one? ! ',
body: 'Another one! ',
author: 'Elke',
datePosted: new Date(2019, 1, 20),
},
];
}
</script>
Copy the code
Run the project:
This is a simple parent-child component
6. Refer to articles
TypeScript — JavaScript with superpowers — Part II
VUE WITH TYPESCRIPT
TypeScript + for large projects
Python modifier (1) — function modifier “@”
What’s the difference between interface and type in Typescript
7. To summarize
Class API
class
Vue
Ts
Class API
❤️ see three things
If you found this post inspiring, I’d like to invite you to do three small favors for me:
- Like, let more people can also see this content (collection does not like, is playing rogue – -)
- Pay attention to the public number “front-end dispeller”, irregularly share original knowledge.
- Check out other articles as well
- Design Patterns you Inadvertently Use (part 1) – Creation patterns
- “King of data visualization library” D3.js fast start to Vue application
- “True ® Path to Full Stack” a back-end guide to Web front-end development
- “Vue Practice” 5 minutes for a Vue CLI plug-in
- “Vue practices” arm your front-end projects
- “Advanced front end interview” JavaScript handwriting unbeatable secrets
- “Learn from source code” answers to Vue questions that interviewers don’t know
- “Learn from the source code” Vue source code in JS SAO operation
- “Vue Practice” project to upgrade vue-CLI3 correct posture
- Why do you never understand JavaScript scope chains?
You can also go to my GitHub blog and get the source files for all the posts:
Front end exit guide: github.com/roger-hiro/…