Vue新搭檔TypeScript快速入門(mén)實(shí)踐記錄
Vue官方從2.6.X版本開(kāi)始就部分使用Ts重寫(xiě)了。
我個(gè)人對(duì)更嚴(yán)格類(lèi)型限制沒(méi)有積極的看法,畢竟各類(lèi)轉(zhuǎn)類(lèi)型的騷寫(xiě)法寫(xiě)習(xí)慣了。
最近的一個(gè)項(xiàng)目中,是TypeScript+ Vue,毛計(jì)喇,學(xué)之...…真香!
注意此篇標(biāo)題的“前”,本文旨在講Ts混入框架的使用,不講Class API
1. 使用官方腳手架構(gòu)建
npm install -g @vue/cli # OR yarn global add @vue/cli
新的Vue CLI工具允許開(kāi)發(fā)者 使用 TypeScript 集成環(huán)境 創(chuàng)建新項(xiàng)目。
只需運(yùn)行vue create my-app。
然后,命令行會(huì)要求選擇預(yù)設(shè)。使用箭頭鍵選擇Manually select features。
接下來(lái),只需確保選擇了TypeScript和Babel選項(xiàng),如下圖:

完成此操作后,它會(huì)詢(xún)問(wèn)你是否要使用class-style component syntax。
然后配置其余設(shè)置,使其看起來(lái)如下圖所示。

Vue CLI工具現(xiàn)在將安裝所有依賴(lài)項(xiàng)并設(shè)置項(xiàng)目。

接下來(lái)就跑項(xiàng)目

2. 項(xiàng)目目錄解析
通過(guò)tree指令查看目錄結(jié)構(gòu)后可發(fā)現(xiàn)其結(jié)構(gòu)和正常構(gòu)建的大有不同。

這里主要關(guān)注shims-tsx.d.ts和 shims-vue.d.ts兩個(gè)文件
兩句話概括:
shims-tsx.d.ts,允許你以.tsx結(jié)尾的文件,在Vue項(xiàng)目中編寫(xiě)jsx代碼shims-vue.d.ts主要用于TypeScript識(shí)別.vue文件,Ts默認(rèn)并不支持導(dǎo)入vue文件,這個(gè)文件告訴ts導(dǎo)入.vue文件都按VueConstructor<Vue>處理。
此時(shí)我們打開(kāi)親切的src/components/HelloWorld.vue,將會(huì)發(fā)現(xiàn)寫(xiě)法已大有不同
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<!-- 省略 -->
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
@Component
export default class HelloWorld extends Vue {
@Prop() private msg!: string;
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>至此,準(zhǔn)備開(kāi)啟新的篇章 TypeScript極速入門(mén) 和 vue-property-decorator
3. TypeScript極速入門(mén)
3.1 基本類(lèi)型和擴(kuò)展類(lèi)型
Typescript與Javascript共享相同的基本類(lèi)型,但有一些額外的類(lèi)型。
- 元組
Tuple - 枚舉
enum Any與Void
1. 基本類(lèi)型合集
// 數(shù)字,二、八、十六進(jìn)制都支持
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
// 字符串,單雙引都行
let name: string = "bob";
let sentence: string = `Hello, my name is ${ name }.
// 數(shù)組,第二種方式是使用數(shù)組泛型,Array<元素類(lèi)型>:
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
let u: undefined = undefined;
let n: null = null;2. 特殊類(lèi)型
1. 元組 Tuple
想象 元組 作為有組織的數(shù)組,你需要以正確的順序預(yù)定義數(shù)據(jù)類(lèi)型。
const messyArray = [' something', 2, true, undefined, null]; const tuple: [number, string, string] = [24, "Indrek" , "Lasn"]
如果不遵循 為元組 預(yù)設(shè)排序的索引規(guī)則,那么Typescript會(huì)警告。

? (tuple第一項(xiàng)應(yīng)為number類(lèi)型)
2. 枚舉 enum
enum類(lèi)型是對(duì)JavaScript標(biāo)準(zhǔn)數(shù)據(jù)類(lèi)型的一個(gè)補(bǔ)充。 像C#等其它語(yǔ)言一樣,使用枚舉類(lèi)型可以為一組數(shù)值賦予友好的名字。
// 默認(rèn)情況從0開(kāi)始為元素編號(hào),也可手動(dòng)為1開(kāi)始
enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;
let colorName: string = Color[2];
console.log(colorName); // 輸出'Green'因?yàn)樯厦娲a里它的值是2另一個(gè)很好的例子是使用枚舉來(lái)存儲(chǔ)應(yīng)用程序狀態(tài)。

3. Void
在Typescript中,你必須在函數(shù)中定義返回類(lèi)型。像這樣:

若沒(méi)有返回值,則會(huì)報(bào)錯(cuò):

我們可以將其返回值定義為void:

此時(shí)將無(wú)法 return
4. Any
emmm...就是什么類(lèi)型都行,當(dāng)你無(wú)法確認(rèn)在處理什么類(lèi)型時(shí)可以用這個(gè)。
但要慎重使用,用多了就失去使用Ts的意義。
let person: any = "前端勸退師" person = 25 person = true
主要應(yīng)用場(chǎng)景有:
- 接入第三方庫(kù)
- Ts菜前期都用
5. Never
用很粗淺的話來(lái)描述就是:"Never是你永遠(yuǎn)得不到的爸爸。"
具體的行為是:
throw new Error(message)return error("Something failed")while (true) {} // 存在無(wú)法達(dá)到的終點(diǎn)

3. 類(lèi)型斷言
簡(jiǎn)略的定義是:可以用來(lái)手動(dòng)指定一個(gè)值的類(lèi)型。
有兩種寫(xiě)法,尖括號(hào)和as:
let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length; let strLength: number = (someValue as string).length;
使用例子有:
當(dāng) TypeScript 不確定一個(gè)聯(lián)合類(lèi)型的變量到底是哪個(gè)類(lèi)型的時(shí)候,我們只能訪問(wèn)此聯(lián)合類(lèi)型的所有類(lèi)型里共有的屬性或方法:
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'.如果你訪問(wèn)長(zhǎng)度將會(huì)報(bào)錯(cuò),而有時(shí)候,我們確實(shí)需要在還不確定類(lèi)型的時(shí)候就訪問(wèn)其中一個(gè)類(lèi)型的屬性或方法,此時(shí)需要斷言才不會(huì)報(bào)錯(cuò):
function getLength(something: string | number): number {
if ((<string>something).length) {
return (<string>something).length;
} else {
return something.toString().length;
}
}3.2 泛型:Generics
軟件工程的一個(gè)主要部分就是構(gòu)建組件,構(gòu)建的組件不僅需要具有明確的定義和統(tǒng)一的接口,同時(shí)也需要組件可復(fù)用。支持現(xiàn)有的數(shù)據(jù)類(lèi)型和將來(lái)添加的數(shù)據(jù)類(lèi)型的組件為大型軟件系統(tǒng)的開(kāi)發(fā)過(guò)程提供很好的靈活性。
在C#和Java中,可以使用"泛型"來(lái)創(chuàng)建可復(fù)用的組件,并且組件可支持多種數(shù)據(jù)類(lèi)型。這樣便可以讓用戶(hù)根據(jù)自己的數(shù)據(jù)類(lèi)型來(lái)使用組件。
1. 泛型方法
在TypeScript里,聲明泛型方法有以下兩種方式:
function gen_func1<T>(arg: T): T {
return arg;
}
// 或者
let gen_func2: <T>(arg: T) => T = function (arg) {
return arg;
}調(diào)用方式也有兩種:
gen_func1<string>('Hello world');
gen_func2('Hello world');
// 第二種調(diào)用方式可省略類(lèi)型參數(shù),因?yàn)榫幾g器會(huì)根據(jù)傳入?yún)?shù)來(lái)自動(dòng)識(shí)別對(duì)應(yīng)的類(lèi)型。2. 泛型與Any
Ts 的特殊類(lèi)型 Any 在具體使用時(shí),可以代替任意類(lèi)型,咋一看兩者好像沒(méi)啥區(qū)別,其實(shí)不然:
// 方法一:帶有any參數(shù)的方法
function any_func(arg: any): any {
console.log(arg.length);
return arg;
}
// 方法二:Array泛型方法
function array_func<T>(arg: Array<T>): Array<T> {
console.log(arg.length);
return arg;
}- 方法一,打印了
arg參數(shù)的length屬性。因?yàn)?code>any可以代替任意類(lèi)型,所以該方法在傳入?yún)?shù)不是數(shù)組或者帶有length屬性對(duì)象時(shí),會(huì)拋出異常。 - 方法二,定義了參數(shù)類(lèi)型是
Array的泛型類(lèi)型,肯定會(huì)有length屬性,所以不會(huì)拋出異常。
3. 泛型類(lèi)型
泛型接口:
interface Generics_interface<T> {
(arg: T): T;
}
function func_demo<T>(arg: T): T {
return arg;
}
let func1: Generics_interface<number> = func_demo;
func1(123); // 正確類(lèi)型的實(shí)際參數(shù)
func1('123'); // 錯(cuò)誤類(lèi)型的實(shí)際參數(shù)3.3 自定義類(lèi)型:Interface vs Type alias
Interface,國(guó)內(nèi)翻譯成接口。
Type alias,類(lèi)型別名。
1. 相同點(diǎn)
都可以用來(lái)描述一個(gè)對(duì)象或函數(shù):
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;都允許拓展(extends):
interface 和 type 都可以拓展,并且兩者并不是相互獨(dú)立的,也就是說(shuō)interface可以 extends type, type 也可以 extends interface 。 雖然效果差不多,但是兩者語(yǔ)法不同。
interface extends interface
interface Name {
name: string;
}
interface User extends Name {
age: number;
}type extends type
type Name = {
name: string;
}
type User = Name & { age: number };interface extends type
type Name = {
name: string;
}
interface User extends Name {
age: number;
}type extends interface
interface Name {
name: string;
}
type User = Name & {
age: number;
}2. 不同點(diǎn)
type 可以而 interface 不行
type 可以聲明基本類(lèi)型別名,聯(lián)合類(lèi)型,元組等類(lèi)型
// 基本類(lèi)型別名
type Name = string
// 聯(lián)合類(lèi)型
interface Dog {
wong();
}
interface Cat {
miao();
}
type Pet = Dog | Cat
// 具體定義數(shù)組每個(gè)位置的類(lèi)型
type PetList = [Dog, Pet]type 語(yǔ)句中還可以使用 typeof獲取實(shí)例的 類(lèi)型進(jìn)行賦值
// 當(dāng)你想獲取一個(gè)變量的類(lèi)型時(shí),使用 typeof
let div = document.createElement('div');
type B = typeof div其他騷操作
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> };interface可以而 type不行
interface 能夠聲明合并
interface User {
name: string
age: number
}
interface User {
sex: string
}
/*
User 接口為 {
name: string
age: number
sex: string
}
*/interface 有可選屬性和只讀屬性
可選屬性
接口里的屬性不全都是必需的。 有些是只在某些條件下存在,或者根本不存在。 例如給函數(shù)傳入的參數(shù)對(duì)象中只有部分屬性賦值了。帶有可選屬性的接口與普通的接口定義差不多,只是在可選屬性名字定義的后面加一個(gè)?符號(hào)。如下所示
interface Person {
name: string;
age?: number;
gender?: number;
}只讀屬性
顧名思義就是這個(gè)屬性是不可寫(xiě)的,對(duì)象屬性只能在對(duì)象剛剛創(chuàng)建的時(shí)候修改其值。 你可以在屬性名前用 readonly來(lái)指定只讀屬性,如下所示:
interface User {
readonly loginName: string;
password: string;
}上面的例子說(shuō)明,當(dāng)完成User對(duì)象的初始化后loginName就不可以修改了。
3.4 實(shí)現(xiàn)與繼承:implements vs extends
extends很明顯就是ES6里面的類(lèi)繼承,那么implement又是做什么的呢?它和extends有什么不同?
implement,實(shí)現(xiàn)。與C#或Java里接口的基本作用一樣,TypeScript也能夠用它來(lái)明確的強(qiáng)制一個(gè)類(lèi)去符合某種契約
implement基本用法:
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';
}而extends是繼承父類(lèi),兩者其實(shí)可以混著用:
class A extends B implements C,D,E
搭配 interface和type的用法有:

3.5 聲明文件與命名空間:declare 和 namespace
前面我們講到Vue項(xiàng)目中的shims-tsx.d.ts和shims-vue.d.ts,其初始內(nèi)容是這樣的:
// 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;
}declare:當(dāng)使用第三方庫(kù)時(shí),我們需要引用它的聲明文件,才能獲得對(duì)應(yīng)的代碼補(bǔ)全、接口提示等功能。
這里列舉出幾個(gè)常用的:
declare var 聲明全局變量
declare function 聲明全局方法
declare class 聲明全局類(lèi)
declare enum 聲明全局枚舉類(lèi)型
declare global 擴(kuò)展全局變量
declare module 擴(kuò)展模塊
namespace:“內(nèi)部模塊”現(xiàn)在稱(chēng)做“命名空間”
module X { 相當(dāng)于現(xiàn)在推薦的寫(xiě)法 namespace X {)
跟其他 JS 庫(kù)協(xié)同
類(lèi)似模塊,同樣也可以通過(guò)為其他 JS 庫(kù)使用了命名空間的庫(kù)創(chuàng)建 .d.ts 文件的聲明文件,如為 D3 JS 庫(kù),可以創(chuàng)建這樣的聲明文件:
declare namespace D3{
export interface Selectors { ... }
}
declare var d3: D3.Base;所以上述兩個(gè)文件:
shims-tsx.d.ts, 在全局變量global中批量命名了數(shù)個(gè)內(nèi)部模塊。shims-vue.d.ts,意思是告訴TypeScript*.vue后綴的文件可以交給vue模塊來(lái)處理。
3.6 訪問(wèn)修飾符:private、public、protected
其實(shí)很好理解:
- 默認(rèn)為
public - 當(dāng)成員被標(biāo)記為
private時(shí),它就不能在聲明它的類(lèi)的外部訪問(wèn),比如:
class Animal {
private name: string;
constructor(theName: string) {
this.name = theName;
}
}
let a = new Animal('Cat').name; //錯(cuò)誤,‘name'是私有的protected和private類(lèi)似,但是,protected成員在派生類(lèi)中可以訪問(wèn)
class Animal {
protected name: string;
constructor(theName: string) {
this.name = theName;
}
}
class Rhino extends Animal {
constructor() {
super('Rhino');
}
getName() {
console.log(this.name) //此處的name就是Animal類(lèi)中的name
}
}3.7 可選參數(shù) ( ?: )和非空斷言操作符(!.)
可選參數(shù)
function buildName(firstName: string, lastName?: string) {
return firstName + ' ' + lastName
}
// 錯(cuò)誤演示
buildName("firstName", "lastName", "lastName")
// 正確演示
buildName("firstName")
// 正確演示
buildName("firstName", "lastName")非空斷言操作符:
能確定變量值一定不為空時(shí)使用。
與可選參數(shù) 不同的是,非空斷言操作符不會(huì)防止出現(xiàn) null 或 undefined。
let s = e!.name; // 斷言e是非空并訪問(wèn)name屬性
拓展
1. 屬性或參數(shù)中使用 ?:表示該屬性或參數(shù)為可選項(xiàng)
2. 屬性或參數(shù)中使用 ?。罕硎緩?qiáng)制解析(告訴typescript編譯器,這里一定有值),常用于vue-decorator中的@Prop
3. 變量后使用 ?。罕硎绢?lèi)型推斷排除null、undefined
4. Vue組件的Ts寫(xiě)法
從 vue2.5 之后,vue 對(duì) ts 有更好的支持。根據(jù)官方文檔,vue 結(jié)合 typescript ,有兩種書(shū)寫(xiě)方式:
Vue.extend
import Vue from 'vue'
const Component = Vue.extend({
// type inference enabled
})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 }理想情況下,Vue.extend 的書(shū)寫(xiě)方式,是學(xué)習(xí)成本最低的。在現(xiàn)有寫(xiě)法的基礎(chǔ)上,幾乎 0 成本的遷移。
但是Vue.extend模式,需要與mixins 結(jié)合使用。在 mixin 中定義的方法,不會(huì)被 typescript 識(shí)別到
,這就意味著會(huì)出現(xiàn)丟失代碼提示、類(lèi)型檢查、編譯報(bào)錯(cuò)等問(wèn)題。
菜鳥(niǎo)才做選擇,大佬都挑最好的。直接講第二種吧:
4.1 vue-class-component

我們回到
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
export default class HelloWorld extends Vue {
@Prop() private msg!: string;
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>有寫(xiě)過(guò)python的同學(xué)應(yīng)該會(huì)發(fā)現(xiàn)似曾相識(shí):
vue-property-decorator這個(gè)官方支持的庫(kù)里,提供了函數(shù) **裝飾器(修飾符)**語(yǔ)法
1. 函數(shù)修飾符 @
“@”,與其說(shuō)是修飾函數(shù)倒不如說(shuō)是引用、調(diào)用它修飾的函數(shù)。
或者用句大白話描述:@: "下面的被我包圍了。"
舉個(gè)栗子,下面的一段代碼,里面兩個(gè)函數(shù),沒(méi)有被調(diào)用,也會(huì)有輸出結(jié)果:
test(f){
console.log("before ...");
f()
console.log("after ...");
}
@test
func(){
console.log("func was called");
}直接運(yùn)行,輸出結(jié)果:
before ...
func was called
after ...
上面代碼可以看出來(lái):
- 只定義了兩個(gè)函數(shù):
test和func,沒(méi)有調(diào)用它們。 - 如果沒(méi)有 @test,運(yùn)行應(yīng)該是沒(méi)有任何輸出的。
但是,解釋器讀到函數(shù)修飾符“@”的時(shí)候,后面步驟會(huì)是這樣:
- 去調(diào)用
test函數(shù),test函數(shù)的入口參數(shù)就是那個(gè)叫“func”的函數(shù); test函數(shù)被執(zhí)行,入口參數(shù)的(也就是func函數(shù))會(huì)被調(diào)用(執(zhí)行);
換言之,修飾符帶的那個(gè)函數(shù)的入口參數(shù),就是下面的那個(gè)整個(gè)的函數(shù)。有點(diǎn)兒類(lèi)似JavaScript里面的 function a (function () { ... });
2. vue-property-decorator和vuex-class提供的裝飾器
vue-property-decorator的裝飾器:
- @Prop
- @PropSync
- @Provide
- @Model
- @Watch
- @Inject
- @Provide
- @Emit
- @Component (provided by vue-class-component)
- Mixins (the helper function named mixins provided by vue-class-component)
vuex-class的裝飾器:
- @State
- @Getter
- @Action
- @Mutation
我們拿原始Vue組件模版來(lái)看:
import {componentA,componentB} from '@/components';
export default {
components: { componentA, componentB},
props: {
propA: { type: Number },
propB: { default: 'default value' },
propC: { type: [String, Boolean] },
}
// 組件數(shù)據(jù)
data () {
return {
message: 'Hello'
}
},
// 計(jì)算屬性
computed: {
reversedMessage () {
return this.message.split('').reverse().join('')
}
// Vuex數(shù)據(jù)
step() {
return this.$store.state.count
}
},
methods: {
changeMessage () {
this.message = "Good bye"
},
getName() {
let name = this.$store.getters['person/name']
return name
}
},
// 生命周期
created () { },
mounted () { },
updated () { },
destroyed () { }
}以上模版替換成修飾符寫(xiě)法則是:
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) readonly propA!: number | undefined
@Prop({ default: 'default value' }) readonly propB!: string
@Prop([String, Boolean]) readonly propC!: string | boolean | undefined
// 原data
message = 'Hello'
// 計(jì)算屬性
private get reversedMessage (): string[] {
return this.message.split('').reverse().join('')
}
// Vuex 數(shù)據(jù)
@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
return storeName
}
// 生命周期
private created ():void { },
private mounted ():void { },
private updated ():void { },
private destroyed ():void { }
}正如你所看到的,我們?cè)谏芷?列表那都添加private XXXX方法,因?yàn)檫@不應(yīng)該公開(kāi)給其他組件。
而不對(duì)method做私有約束的原因是,可能會(huì)用到@Emit來(lái)向父組件傳遞信息。
4.2 添加全局工具
引入全局模塊,需要改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');npm i VueI18n
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
// 新模塊
import i18n from './i18n';
Vue.config.productionTip = false;
new Vue({
router,
store,
i18n, // 新模塊
render: (h) => h(App),
}).$mount('#app');但僅僅這樣,還不夠。你需要?jiǎng)?code>src/vue-shim.d.ts:
// 聲明全局方法
declare module 'vue/types/vue' {
interface Vue {
readonly $i18n: VueI18Next;
$t: TranslationFunction;
}
}之后使用this.$i18n()的話就不會(huì)報(bào)錯(cuò)了。
4.3 Axios 使用與封裝
Axios的封裝千人千面
如果只是想簡(jiǎn)單在Ts里體驗(yàn)使用Axios,可以安裝vue-axios 簡(jiǎn)單使用Axios
$ npm i axios vue-axios
main.ts添加:
import Vue from 'vue' import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios, axios)
然后在組件內(nèi)使用:
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)
})1. 新建文件request.ts
文件目錄:
-api
- main.ts // 實(shí)際調(diào)用
-utils
- request.ts // 接口封裝2. request.ts文件解析
import * as axios from 'axios';
import store from '@/store';
// 這里可根據(jù)具體使用的UI組件庫(kù)進(jìn)行替換
import { Toast } from 'vant';
import { AxiosResponse, AxiosRequestConfig } from 'axios';
/* baseURL 按實(shí)際項(xiàng)目來(lái)定義 */
const baseURL = process.env.VUE_APP_URL;
/* 創(chuàng)建axios實(shí)例 */
const service = axios.default.create({
baseURL,
timeout: 0, // 請(qǐng)求超時(shí)時(shí)間
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('請(qǐng)求錯(cuò)誤!');
} else {
return response.data;
}
},
(error: any) => {
return Promise.reject(error);
});
export default service;為了方便,我們還需要定義一套固定的 axios 返回的格式,新建ajax.ts:
export interface AjaxResponse {
code: number;
data: any;
message: string;
}3. main.ts接口調(diào)用:
// api/main.ts
import request from '../utils/request';
// get
export function getSomeThings(params:any) {
return request({
url: '/api/getSomethings',
});
}
// post
export function postSomeThings(params:any) {
return request({
url: '/api/postSomethings',
methods: 'post',
data: params
});
}5. 編寫(xiě)一個(gè)組件
為了減少時(shí)間,我們來(lái)替換掉src/components/HelloWorld.vue,做一個(gè)博客帖子組件:
<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';
// 在這里對(duì)數(shù)據(jù)進(jìn)行類(lèi)型約束
export interface Post {
title: string;
body: string;
author: string;
datePosted: Date;
}
@Component
export default class HelloWorld extends Vue {
@Prop() private post!: Post;
get date() {
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>然后在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>
這時(shí)候運(yùn)行項(xiàng)目:

這就是簡(jiǎn)單的父子組件

而關(guān)于
Class API撤銷(xiāo),其實(shí)還是挺舒服的。 用class來(lái)編寫(xiě)Vue組件確實(shí)太奇怪了。 (所以本篇Ts入門(mén)壓根沒(méi)寫(xiě)Class API)
以上就是Vue新搭檔TypeScript快速入門(mén)實(shí)踐的詳細(xì)內(nèi)容,更多關(guān)于Vue TypeScript快速入門(mén)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue/React子組件實(shí)例暴露方法(TypeScript)
最近幾個(gè)月都在用TS開(kāi)發(fā)各種項(xiàng)目,框架有涉及到Vue3,React18等,記錄一下Vue/React組件暴露出變量/函數(shù)的方法的寫(xiě)法,對(duì)vue?react組件暴露方法相關(guān)知識(shí)感興趣的朋友跟隨小編一起看看吧2022-11-11
Vue循環(huán)中多個(gè)input綁定指定v-model實(shí)例
這篇文章主要介紹了Vue循環(huán)中多個(gè)input綁定指定v-model實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
vue+element實(shí)現(xiàn)表單校驗(yàn)功能
這篇文章主要介紹了vue+element表單校驗(yàn)功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05
前端利用vue實(shí)現(xiàn)導(dǎo)入和導(dǎo)出功能詳細(xì)代碼
最近項(xiàng)目中讓實(shí)現(xiàn)一個(gè)導(dǎo)入導(dǎo)出Excel的功能,下面這篇文章主要給大家介紹了關(guān)于前端利用vue實(shí)現(xiàn)導(dǎo)入和導(dǎo)出功能的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09
vue-cli構(gòu)建項(xiàng)目使用 less的方法
這篇文章主要介紹了vue-cli構(gòu)建項(xiàng)目使用 less,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
在Vue中實(shí)現(xiàn)網(wǎng)頁(yè)截圖與截屏功能詳解
在Web開(kāi)發(fā)中,有時(shí)候需要對(duì)網(wǎng)頁(yè)進(jìn)行截圖或截屏,Vue作為一個(gè)流行的JavaScript框架,提供了一些工具和庫(kù),可以方便地實(shí)現(xiàn)網(wǎng)頁(yè)截圖和截屏功能,本文將介紹如何在Vue中進(jìn)行網(wǎng)頁(yè)截圖和截屏,需要的朋友可以參考下2023-06-06
Vue中為什么要引入render函數(shù)的實(shí)現(xiàn)
本文主要介紹了Vue中為什么要引入render函數(shù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01

