Best practices for getting started with TypeScript before Vue3.0
December 18, 2023
by Sarah McKay
No Comments
preface
Actually,VueThe official fromX 2.6.Version begins with partial useTsRewritten.
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.tsYou are allowed to.tsxAt the end of the fileVueWrite in a projectjsxcode
shims-vue.d.tsIt is mainly used forTypeScriptidentify.vueFile,TsImport is not supported by defaultvueThe file, the file tellstsThe import.vueFiles 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. TypeScriptIntroduction to speed
3.1 Basic types and extension types
Typescript shares the same basic types as Javascript, but there are a few additional types.
tuplesTuple
The enumerationenum
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.
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 = trueCopy 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 printedargParameters of thelengthProperties. becauseanyCan be substituted for any type, so the method is passed either an array or withlengthProperty object, an exception is thrown.
Method two defines the parameter type isArrayFor generic types, there must belengthProperty, 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
typeCan theinterfaceno
typeYou 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
typeStatement can also be usedtypeofGets 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
interfaceCan thetypeno
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:implementsvsextends
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:
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 variablesdeclarefunctionDeclaring 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 variableglobalSeveral internal modules are batch named in
shims-vue.d.ts“Means to tellTypeScript*.vueSuffixed files can be handed invueModule 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
protectedandprivateSimilar, but,protectedMembers 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 (! .).
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