Ts简介
TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准。应用到ts无疑是看重这几个优点:
- 静态类型检查和类型推断
- IDE 智能提示
- 代码重构
- 可读性 废话少说,上代码
//常见类型有 string,number,boolean,undefined,null,symbol
//举个栗子
let a:string;
a = "测试"; //正确
a = 2; //错误
// 当然编译器类型的推断,可省略冒号后面这个语法
let b = true;
// b = 2; // 错误
//类型数组
let arr: string[];
arr = ["joe"];
//其中any类型也可用于数组
let arrAny: any[];
arrAny = [2, false, "hello"];
arrAny[1] = 10;
// any类型
let varAny: any;
varAny = "world"; //正确
varAny = 3; //正确
// 在函数中的类型约束
function person(name: string): string {
return "hello, " + name;
}
// void类型,常用于没有返回值的函数
function fun(): void {}
//类型别名 和交叉类型
type obj = {foo:string;bar:string};
let objType:obj;
objType = {foo:"foo",bar:"bar"};
type OBJ = obj & {flag:boolen};
// 联合类型
let union: string | number;
union = "2";
union = 2;
// 函数
// 1.形参声明就是必填项
// 2.?表示可选
function person(name: string, age = 20, sex?: string): string {
return "Hello, " + name;
}
person("joe");
// 接口:只定义结构,不定义实现
interface NANE {
firstName: string;
lastName: string;
}
function person(name: NANE) {
return "Hello, " + NANE.firstName + " " + NANE.lastName;
}
person({ firstName: "Jane", lastName: "User" }); // 正确
// person({firstName: 'Jane'}); // 错误
// 泛型优点:
// 函数和类可以⽀持多种类型,更加通⽤
// 不必编写多条重载,冗⻓联合类型,可读性好
// 灵活控制类型约束
// 不仅通⽤且能灵活控制,泛型被⼴泛⽤于通⽤库的编写
// 泛型
interface msg<T> {
code: 0 | 1;
data: T;
}
// 泛型⽅法
function getMsg<T>(data: T): msg<T> {
return {code:1, data};
}
getMsg<string>('haha')
大概列举了以上一些常见的用法,想了解更多的语法的,请上ts中文手册查看,此外介绍一款好用的工具:ts演习场
如何应用
1、在已存的vue2项目中,运行 vue add @vue/typescript.这种方式就像运行插件一样,勾选你所选需要的配置就好了。
2、新建项目时,vue create XXX,也会出现ts的勾选和vue2和vue3的配置勾选,大家按需所求。
这里我们按照第2种方式来走一遍。运行vue create XXX后,配置大概如下:
等xxx都建好后,我们打开这个项目,回看到这样的目录结构
主要涉及 shims-tsx.d.ts 和 shims-vue.d.ts 两个文件
shims-tsx.d.ts,允许你以.tsx结尾的文件,在Vue项目中编写jsx代码shims-vue.d.ts是为了typescript做的适配定义文件,因为.vue文件不是一个常规的文件类型,ts 是不能理解 vue 文件是干嘛的.
/**
* shims-vue.d.ts的作用
* 为了 typescript 做的适配定义文件,因为.vue 文件不是一个常规的文件类型,ts 是不能理解 vue 文件是干嘛的,
* 加这一段是是告诉 ts,vue 文件是这种类型的。
* 可以把这一段删除,会发现 import 的所有 vue 类型的文件都会报错。
*/
declare module '*.vue' { //declare声明宣告, 声明一个ambient module(即:没有内部实现的 module声明)
import Vue from 'vue'
export default Vue
}
declare module 'vue-echarts' // 引入vue-echarts
<script lang="ts">
/* eslint-disable @typescript-eslint/camelcase */
import { Vue, Component, Watch } from 'vue-property-decorator'
import ECharts from 'vue-echarts' //报错,按上面的方法在shims-vue.d.ts文件中引入即可
import 'echarts/lib/chart/line'
import 'echarts/lib/chart/pie'
import 'echarts/lib/component/tooltip'
</script>
然后我们点进去Home组件中,可以发现它的写法跟以前不太一样了。
vue-class-component 是官方推出的vue对typescript支持的装饰器(库),可以将Vue中的组件用类的方式编写,vue-property-decorator是vue-class-component 的超集。
这个组件完全依赖于
vue-class-component.它具备以下几个属性:
- @Component (完全继承于
vue-class-component) - @Emit
- @Inject
- @Provice
- @Prop
- @Watch
- @Model
- Mixins (在
vue-class-component中定义); 更多装饰器的用法可以参考官网文档和掘金# 曾小曾的文章
用法 & 栗子
1、修改Home父组件的代码
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App" @add-feature="addFeature"/>
</div>
</template>
//Vue页面中的script部分要加一个lang=ts,这样安装好typescript正能引用
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
//FeatureSelected是从HelloWorld子组件曝光出来的类型结构
import HelloWorld, { FeatureSelected } from '@/components/HelloWorld.vue'
//@Component 类装饰器 挂载HelloWorld组件
@Component({
components: {
HelloWorld
}
})
export default class Home extends Vue {
// 监听HelloWorld子组件
private addFeature (feature: FeatureSelected) {
// HelloWorld子组件传过来的值
console.log('add a new feature:', feature.name)
}
}
</script>
2、魔改Helloworld子组件的代码
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<ul>
<li v-for="item in features" :key="item.id">{{item.name}}</li>
<li>特性总数:{{ count }}</li>
</ul>
<p><input type="text" @keydown.enter="addFeature"></p>
</div>
</template>
<script lang="ts">
// 导入所需的装饰器
import { Component, Prop, Vue, Emit, Watch } from 'vue-property-decorator'
// 类型别名
type Feature = {
id:number;
name:string;
};
// 导出交叉类型
export type FeatureSelected = Feature & {selected:boolean};
// 泛型
interface Result<T> {
ok: 0 | 1;
data:T;
};
// 泛型方法采用promise
function getResult<T> (): Promise<Result<T>> {
const data: any = [
{ id: 1, name: '111', selected: false },
{ id: 2, name: '222', selected: true }
]
return Promise.resolve({
ok: 1,
data
})
}
@Component
export default class HelloWorld extends Vue {
// 1、从父组件Home.vue传过来的值,其中!代表这里一定有值,让编译器别瞎操心。
// 2、但如果写?的时候再调用,typescript会提示可能为undefined
// 3、如果有多个不同的值传过来,可以写多个 @Prop
@Prop() private msg!: string;
// 相当于定义data值
features:FeatureSelected[] = [];
// 生命钩子
async created () {
this.features = (await getResult<FeatureSelected[]>()).data
}
// 监听 - 装饰器
@Watch('features')
private onFeauturesChange (val, old) {
// 输出变化后的值
console.log(val)
console.log(val)
}
// @Emit装饰器 - 向父组件传递信息
@Emit()
addFeature (e:KeyboardEvent) {
// 断言,可以由用户判断其类型
const inp = e.target as HTMLInputElement
console.log(inp.value)
const feature: FeatureSelected = {
id: this.features.length + 1,
name: inp.value,
selected: false
}
this.features.push(feature)
inp.value = ''
// 返回值作为参数
return feature
}
// 寄存器作为计算属性
get count () {
return this.features.length
}
}
</script>