vue中的应用场景
tsconfig注意事项
留神你须要引入 strict: true (或者至多 noImplicitThis: true,这是 strict 模式的一部分) 以利用组件办法中 this 的类型查看,否则它会始终被看作 any 类型。
须要留神以下的配置项,不然类型推断不能失常运作
// 启用所有严格类型查看选项"strict": true,// 禁止this 值为 any"noImplicitThis": true,
Vue.extend()的作用
vue.extend办法曾经申明了参数类型,所以vue.extend能够为你提供类型推断。
举个例子,看上面一段代码:
type vueExtend = (option: { name: string, $store: object, $route: object }) => void;const vueInstance: vueExtend = ({ $ }) {};
vue原型混入属性或办法
平时咱们写的 $store 或 $route 等办法插件向vue原型中增加了原型属性$store和$route。
那如何在ts中的vue原型中混入这些属性或办法呢?
从vuex导出的ts申明文件,咱们能够看到下代码:
import Vue, { ComponentOptions } from "vue";import { Store } from "./index";declare module "vue/types/options" { interface ComponentOptions<V extends Vue> { store?: Store<any>; }}declare module "vue/types/vue" { interface Vue { $store: Store<any>; }}
所以如果咱们想混入$api的话也是须要这么做的。
先去新建一个global.d.ts,应用以下的代码
declare module "vue/types/vue" { interface Vue { $api: { queryHotel: <T>(options: any) => Promise<T>; }; } // 应用this.$api.queryHotel(payload).then(() => {});
推断vue组件实例类型
为什么须要推断vue实例类型,这是有应用场景的。
比方咱们须要拿到子组件的援用,并调用子组件的办法的时候。
假如此时子组件为SpaceDrawer, ref为spaceDrawer。
// 同步移除物联树的节点(this.$refs.spaceDrawer as any).removeCheckNode(delRoomNode[0]);获取SpaceDrawer实例类型type SpaceDrawerRef = InstanceType<typeof SpaceDrawer>;// 同步移除物联树的节点(this.$refs.spaceDrawer as SpaceDrawerRef).removeCheckNode(delRoomNode[0]);
采纳高级类型InstanceType可获得vue组件实例SpaceDrawer。
vue中从新申明data中属性的类型
vue中的类型得益于vue.extend能主动推断类型,然而有时候你须要自定义类型。如下例子
export default Vue.extend({ data() { return { obj: { name: '', value: '' } } }, methods: { handleObj(type: string) { // 这样是能够的 this.obj.name = 'xxx'; // 这样是不行的,(比方type就是name) this.obj[type] = 'xxx' } }})
如上两种状况,第二种显然须要从新定义类型,因为这须要用可索引类型了。
咱们能够对data内的字段从新定义类型,也就是类型断言。
如下:
type ObjType = { [key: string]: string; name: string; value: string }export default Vue.extend({ data() { return { obj: { name: '', value: '' } as ObjType, } }, methods: { handleObj(type: string) { // 这样是能够的 this.obj[type] = 'xxx' } }})
vue中从新申明props的类型
跟data是差不多,只是vue的类型零碎曾经为咱们提供了断言的类型 - PropType
用法如下:
export default Vue.extend({ props: { spaceModel: { type: Number as PropType<SpaceModelEnum>, default: SpaceModelEnum.All, }, spaceOperator: { type: String as PropType<SpaceOperator>, default: SpaceOperator.CREATE, } },}
computed中get,set使类型推断异样
这里须要留神一下,有时候会遇到类型推断不起作用了,并且computed中存在异样。
这是因为computed的异样阻断了类型的进一步推断。
如下状况,此时曾经不能推断出prop外面的属性:
解决办法就是,对这种写法的类型申明补全。
让mixins失去类型推断
让mixins失去类型推断
待更新 ...
枚举让代码更清晰
置信大家都晓得,枚举有两种。
- 一种是常量枚举
- 一种是一般枚举
// 1、常量枚举const enum State { SUCCESS = 0, FAIL }// 2、枚举enum State { SUCCESS = 0, FAIL }
那什么时候用常量枚举,什么时候用一般枚举。
你只须要晓得常量枚举在js运行时是ts编译后的值。
什么意思?
如果你把常量枚举当成一个常量是不行的,因为它并不存在。
enum SpaceModelEnum { All = 0, ONLY_BUILDING_ROOM, ONLY_FLOOR_ROOM, ONLY_ROOM,}const enum SpaceType { BUILDING = 0, FLOOR, ROOM,}export default Vue.extend({ name: 'SpaceCreate', data() { return { // 能够 SpaceModelEnum, // 不行 SpaceType }; },})
枚举用途很大,能够大大提高代码的可读性,当然用map也是能承受的。
switch (level) { case SpaceType.BUILDING: break; case SpaceType.FLOOR: parentNode = spaceDestruct.genBuildingNode(); spaceTree.push(parentNode); break; case SpaceType.ROOM: const buildingNode = spaceDestruct.genAll(); parentNode = buildingNode.children[0]; spaceTree.push(buildingNode); default: break;}
这里能够很分明的晓得level可能是building,floor,room类型。而不是0,1,2这种可读性很低的代码。
ts惯例用法
罕用的ts高级类型
- Record - 常常用的,便捷定义可索引类型,Record<string, { name: string, value: string }>
- ReturnType - 取得函数的返回类型
- ConstructParameter - 获取结构函数参数类型
- typeof - 获得对象的类型等
- keyof - 获取接口类型的key,组合为联结类型
- in - 枚举联结类型
一个优良的ts高级类型开源库:
ts-toolbelt
一篇对于高级类型的博文:
【速查手册】TypeScript 高级类型 cheat sheet
应用泛型动静推断api接口返回的数据类型
不同的申请接口,返回不同的数据类型,那么咱们如何可能定义这种类型呢?咱们很容易想到用泛型。
然而每个接口都会返回固定的格局:
{ code: number; msg: string | null; result: any;}
那么咱们第一步须要把通用的格局抽出来,接下来result就是通过泛型去动静定义了。
这是我封装后的例子。
type ResType<T> = { code: number; msg: string | null; result: T;};api<T>(urlProp: string, params: Record<string, any>, config = {}): Promise<ResType<T>> { const { get: urlGet, post: urlPost } = this.urlObject; let url = urlGet[urlProp]; if (url && url.length > 0) { return ajax.get<T>(url, params, config); } url = urlPost[urlProp]; return ajax.post<T>(url, params, config);}const ajax = { post<T>( url: string, params: Record<string, any>, config: AxiosRequestConfig = {} ): Promise<ResType<T>> { return new Promise((resolve, reject) => { axios.post(url, params, config).then( (res: AxiosResponse) => { const { data = {} } = res; resolve(data); }, (err) => { reject(err); } ); }); },};
如何应用呢?
type HotelSpaceNode = { roomId: string; name: string; parentId: string;}api<HotelSpaceNode[]>('http://debug.aqara.com/getHotelSpaceNode', {}).then(({ code, result }) => { if (code === 0) { // 此时result的类型就是HotelSpaceNode[] this.spaceTreeData = result; } });
类型断言(强制类型转换)
这里有个例子。
比方我定义了空对象,那么我须要往对象中动静退出属性,然而这个对象依赖于某个接口。
怎么做呢?
type mapNodeType = { spaceName: string; spaceId: string; spaceType: number; parentId: string;}const mapNode = <mapNodeType>{};const { level, childrenList, roomId, name, parentId, state, spaceState} = currentNode;mapNode.spaceId = roomId;mapNode.spaceName = name;mapNode.spaceType = level;mapNode.parentId = parentId;
当然下面的例子用类型申明更好一点,不论怎么样,都能提供类型推断和更高的代码可读性。
还有一种是须要赋予默认值的时候。
genFloorNode(spaceNode: FloorSpaceNode = <FloorSpaceNode>{}) { const theSpaceNode = spaceNode; if (_.isEmpty(spaceNode)) { theSpaceNode.spaceType = SpaceType.FLOOR; } return new FloorSpaceNode(theSpaceNode);}