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);
}