在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
我个人对更严格类型限制没有积极的看法,毕竟各类转类型的骚写法写习惯了。 最近的一个项目中,是 注意此篇标题的“前”,本文旨在讲 1. 使用官方脚手架构建npm install -g @vue/cli # OR yarn global add @vue/cli 新的 只需运行 然后,命令行会要求选择预设。使用箭头键选择 接下来,只需确保选择了 完成此操作后,它会询问你是否要使用 然后配置其余设置,使其看起来如下图所示。 Vue CLI工具现在将安装所有依赖项并设置项目。 接下来就跑项目 2. 项目目录解析通过 这里主要关注 两句话概括:
此时我们打开亲切的 <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> 至此,准备开启新的篇章 3. TypeScript极速入门3.1 基本类型和扩展类型
1. 基本类型合集 // 数字,二、八、十六进制都支持 let decLiteral: number = 6; let hexLiteral: number = 0xf00d; // 字符串,单双引都行 let name: string = "bob"; let sentence: string = `Hello, my name is ${ name }. // 数组,第二种方式是使用数组泛型,Array<元素类型>: let list: number[] = [1, 2, 3]; let list: Array<number> = [1, 2, 3]; let u: undefined = undefined; let n: null = null; 2. 特殊类型 1. 元组 想象 元组 作为有组织的数组,你需要以正确的顺序预定义数据类型。 const messyArray = [' something', 2, true, undefined, null]; const tuple: [number, string, string] = [24, "Indrek" , "Lasn"] 如果不遵循 为元组 预设排序的索引规则,那么 ( 2. 枚举
// 默认情况从0开始为元素编号,也可手动为1开始 enum Color {Red = 1, Green = 2, Blue = 4} let c: Color = Color.Green; let colorName: string = Color[2]; console.log(colorName); // 输出'Green'因为上面代码里它的值是2 另一个很好的例子是使用枚举来存储应用程序状态。 3. 在 若没有返回值,则会报错: 我们可以将其返回值定义为 此时将无法 4. emmm...就是什么类型都行,当你无法确认在处理什么类型时可以用这个。 但要慎重使用,用多了就失去使用Ts的意义。 let person: any = "前端劝退师" person = 25 person = true 主要应用场景有:
5. 用很粗浅的话来描述就是:" 具体的行为是:
3. 类型断言 简略的定义是:可以用来手动指定一个值的类型。 有两种写法,尖括号和 let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length; let strLength: number = (someValue as string).length; 使用例子有: 当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法: 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'. 如果你访问长度将会报错,而有时候,我们确实需要在还不确定类型的时候就访问其中一个类型的属性或方法,此时需要断言才不会报错: function getLength(something: string | number): number { if ((<string>something).length) { return (<string>something).length; } else { return something.toString().length; } } 3.2 泛型:Generics软件工程的一个主要部分就是构建组件,构建的组件不仅需要具有明确的定义和统一的接口,同时也需要组件可复用。支持现有的数据类型和将来添加的数据类型的组件为大型软件系统的开发过程提供很好的灵活性。 在 1. 泛型方法 在TypeScript里,声明泛型方法有以下两种方式: function gen_func1<T>(arg: T): T { return arg; } // 或者 let gen_func2: <T>(arg: T) => T = function (arg) { return arg; } 调用方式也有两种: gen_func1<string>('Hello world'); gen_func2('Hello world'); // 第二种调用方式可省略类型参数,因为编译器会根据传入参数来自动识别对应的类型。 2. 泛型与
// 方法一:带有any参数的方法 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; } 3. 泛型类型 泛型接口: 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); // 正确类型的实际参数 func1('123'); // 错误类型的实际参数 3.3 自定义类型:Interface vs Type alias
1. 相同点 都可以用来描述一个对象或函数: 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 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. 不同点
// 基本类型别名 type Name = string // 联合类型 interface Dog { wong(); } interface Cat { miao(); } type Pet = Dog | Cat // 具体定义数组每个位置的类型 type PetList = [Dog, Pet]
// 当你想获取一个变量的类型时,使用 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 User { name: string age: number } interface User { sex: string } /* User 接口为 { name: string age: number sex: string } */
可选属性 接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。 例如给函数传入的参数对象中只有部分属性赋值了。带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个 interface Person { name: string; age?: number; gender?: number; } 只读属性 顾名思义就是这个属性是不可写的,对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 interface User { readonly loginName: string; password: string; } 上面的例子说明,当完成User对象的初始化后loginName就不可以修改了。 3.4 实现与继承:implements vs extends
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'; } 而
搭配 3.5 声明文件与命名空间:declare 和 namespace前面我们讲到Vue项目中的 // 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; }
这里列举出几个常用的:
跟其他 JS 库协同 类似模块,同样也可以通过为其他 JS 库使用了命名空间的库创建 declare namespace D3{ export interface Selectors { ... } } declare var d3: D3.Base; 所以上述两个文件:
3.6 访问修饰符:private、public、protected其实很好理解:
class Animal { private name: string; constructor(theName: string) { this.name = theName; } } let a = new Animal('Cat').name; //错误,‘name'是私有的
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类中的name } } 3.7 可选参数 ( ?: )和非空断言操作符(!.)可选参数 function buildName(firstName: string, lastName?: string) { return firstName + ' ' + lastName } // 错误演示 buildName("firstName", "lastName", "lastName") // 正确演示 buildName("firstName") // 正确演示 buildName("firstName", "lastName") 非空断言操作符: 能确定变量值一定不为空时使用。 与可选参数 不同的是,非空断言操作符不会防止出现 null 或 undefined。 let s = e!.name; // 断言e是非空并访问name属性 拓展
4. Vue组件的Ts写法从 vue2.5 之后,vue 对 ts 有更好的支持。根据官方文档,vue 结合 typescript ,有两种书写方式: 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 } 理想情况下, 但是 ,这就意味着会出现丢失代码提示、类型检查、编译报错等问题。 菜鸟才做选择,大佬都挑最好的。直接讲第二种吧: 4.1 vue-class-component
<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> 有写过
1. 函数修饰符 “@”,与其说是修饰函数倒不如说是引用、调用它修饰的函数。 或者用句大白话描述: 举个栗子,下面的一段代码,里面两个函数,没有被调用,也会有输出结果: test(f){ console.log("before ..."); f() console.log("after ..."); } @test func(){ console.log("func was called"); } 直接运行,输出结果:
上面代码可以看出来:
但是,解释器读到函数修饰符“@”的时候,后面步骤会是这样:
换言之,修饰符带的那个函数的入口参数,就是下面的那个整个的函数。有点儿类似 2.
我们拿原始Vue组件模版来看: import {componentA,componentB} from '@/components'; export default { components: { componentA, componentB}, props: { propA: { type: Number }, propB: { default: 'default value' }, propC: { type: [String, Boolean] }, } // 组件数据 data () { return { message: 'Hello' } }, // 计算属性 computed: { reversedMessage () { return this.message.split('').reverse().join('') } // Vuex数据 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 () { } } 以上模版替换成修饰符写法则是: 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' // 计算属性 private get reversedMessage (): string[] { return this.message.split('').reverse().join('') } // Vuex 数据 @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 { } } 正如你所看到的,我们在生命周期 列表那都添加 而不对 4.2 添加全局工具引入全局模块,需要改 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');
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'); 但仅仅这样,还不够。你需要动 // 声明全局方法 declare module 'vue/types/vue' { interface Vue { readonly $i18n: VueI18Next; $t: TranslationFunction; } } 之后使用 4.3 Axios 使用与封装
如果只是想简单在Ts里体验使用 $ npm i axios vue-axios
import Vue from 'vue' import axios from 'axios' import VueAxios from 'vue-axios' Vue.use(VueAxios, axios) 然后在组件内使用: 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. 新建文件 文件目录: -api - main.ts // 实际调用 -utils - request.ts // 接口封装 2. import * as axios from 'axios'; import store from '@/store'; // 这里可根据具体使用的UI组件库进行替换 import { Toast } from 'vant'; import { AxiosResponse, AxiosRequestConfig } from 'axios'; /* baseURL 按实际项目来定义 */ const baseURL = process.env.VUE_APP_URL; /* 创建axios实例 */ 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('请求错误!'); } else { return response.data; } }, (error: any) => { return Promise.reject(error); }); export default service; 为了方便,我们还需要定义一套固定的 axios 返回的格式,新建 export interface AjaxResponse { code: number; data: any; message: string; } 3. // 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. 编写一个组件 为了减少时间,我们来替换掉 <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'; // 在这里对数据进行类型约束 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> 然后在 <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> 这时候运行项目: 这就是简单的父子组件
以上就是Vue新搭档TypeScript快速入门实践的详细内容,更多关于Vue TypeScript快速入门的资料请关注极客世界其它相关文章! |
请发表评论