福建住房和城乡建设部网站,喊别人做的网站不肯给代码,wordpress插件社交分享,网站做受网站基于 Redux TypeScript 实现强类型检查和对 Json 的数据清理
突然像是打通了任督二脉一样就用了 generics 搞定了之前一直用 any 实现的类型……
关于 Redux 的部分#xff0c;这里不多赘述#xff0c;基本的实现都在这里#xff1a;Redux Toolkit 调用 API 的四种方式 和…基于 Redux TypeScript 实现强类型检查和对 Json 的数据清理
突然像是打通了任督二脉一样就用了 generics 搞定了之前一直用 any 实现的类型……
关于 Redux 的部分这里不多赘述基本的实现都在这里Redux Toolkit 调用 API 的四种方式 和 async thunk 解决 API 调用的依赖问题。
之前的实现方法是这个TS 使用自动提示生成对象中的键不过实现了一下还是稍微麻烦了一些而且 CRUD 中的 Create 操作比较难因为缺乏默认值之后还是换了一种写法。
虽然这里是用的是 react redux不过因为不涉及到渲染部分以及 redux 也可以在非 react 项目中使用所以还是放到 TS 分类中了x
下面就根据自己的经验和目前写的项目讲一下我自己琢磨出来的实现。
对象的类型定义
这种主要是通过 type or interface 去实现具体没什么差别啦不过对于我们来说数据类型是固定的没必要修改对应的数据类型使用 type 就好了。具体用 type 还是 interface还是具体需求具体分析。
另外 type 的优势就是少打一些字……
具体实现如下
export type IPost {body: string;// 因为网上数据和项目数据格式不一致所以这里暂时注释掉// id: number;title: string;userId: number;
};// 这个跟 redux 存储状态相关
// export interface IPostModel extends ISimpleDataFormatIPost {}
export type IRdmMarketModel ISimpleDataFormatIRdmMarket;随后定义一个默认值
export const defaultPost: IPost {body: ,id: 0,title: ,userId: 0,
};这样就完成了最初的设定。
Redux 的类型配置
Redux 的配置就比较复杂了这一个也是比较项目相关的部分下面也会一步步地进行拆解进行实现。
API 传来的数据类型
initialState 还是挺重要的因为我们的 API 有十几二十多个每一个的存储类型都是一致的因此就不可能说将同样的东西 cv 十几二十遍。最终我设计的 Redux 存储格式为
我们的业务是后端绝对会返回一个 data 的数组其中的数据类型大致为
{data: [{type: ,id: 0,attributes: {},// 并不一定存在relationships: {}}],// include 也是外链关系为relationship所包含的entity数据类型与data一致includes: {}
}其中 type 为当前 entity 的名称attributes 为当前 entity 所包含的属性relationship 为可能存在的外链includes 通过 query parameters 调用为 relationship 中外链对象的具体数据。
在具体存储的时候我想把 id 放到 attributes 中这样转化为数组给 UI 组件时会方便一些。于是我定义了 ISimpleDataFormat 的类型
export type IRelationship {data: {type: string;id: number;};
};// 其实这个用 { [key: string]: IRelationship } 的效果应该也是一样的……
export type IRelationships Recordstring, IRelationship;export type ISimpleDataFormatT {attributes: T { id: string };relationships?: IRelationships;
};relationship 我保存了后端传来的数据格式一来没有特别的复杂二来对于 create/update 操作有的时候需要添加 relationship 进行双重验证和建立外链。
Redux 状态的设定
同样我也对 Redux 存储的状态进行了标准化。首先它需要有一个 loading 状态这样可以方便 UI 进行状态的更改同时提醒用户正在拉去数据。其次需要错误的状态同样也是为了显示在 UI 上最后需要分别存储 data 和 included。经过讨论最终决定以 K-V 对的方法存储数据。
最后的状态定义如下
// 也可以使用 Record我之后应该会以 Record 为主毕竟写起来方便些
export type ReduxDataTypeT { [key: string]: T };export type ISliceStateTypeT, U {isLoading: boolean;error: null | SerializedError;data: ReduxDataTypeT;included: ReduxDataTypeU;
};export const initialSliceState {isLoading: false,error: null,data: {},included: {},
};其中 included 可能会存在多个不同的外链不过目前我们只用到了一个所以用 T, U如果之后 included 出现两个以上的外链那么……再改叭……
slice 的实现
这里主要讲一个 fetch其他的操作基本一致没什么特别大的区别。API 方面的话就用网上的 dummy API 了
import { createAsyncThunk, createSlice } from reduxjs/toolkit;
import { initialSliceState } from ../sliceType;
import { ISimpleDataFormat, ISliceStateType } from ../../../types;
import { pick } from lodash;export type IPost {body: string;title: string;userId: number;
};export interface IPostModel extends ISimpleDataFormatIPost {}export const defaultPost: IPost {body: ,title: ,userId: 0,
};export const fetchPost createAsyncThunk(posts/fetch, async () {return fetch(https://jsonplaceholder.typicode.com/posts).then((response) response.json()).then((json) json);
});const postSlice createSlice({name: rdmMarket,initialState: initialSliceState as ISliceStateTypeIPostModel, unknown,reducers: {},extraReducers(builder) {builder.addCase(fetchPost.fulfilled, (state, action) {state.isLoading false;action.payload.forEach((data: IPost { id: string }) {const id String(data.id);const pickedAttributes pick(data, Object.keys(defaultPost)) as IPost;const model: IPostModel {attributes: {id,...pickedAttributes,},};state.data[id] model;});});},
});export const postReducer postSlice.reducer;效果 这里的数据相对而言比较简单因此说使用 pick 对 model 的操作好像有些多余。不过对我们项目来说
后端会自动生成一堆前端用不到的 key比如说创建时间、更新时间、创建对象、版本等这些东西前段用不到存储在状态里就是占用无谓的空间。我们项目数据量还比较大有的时候会有十几二十来万的数据2b 项目非 2c所以能做一点优化就做一点优化。多余的数据传到后端会被 rejected 掉所以对数据的过滤是必须的 如果说一些属性是不需要的直接在 interface 中删掉TS 就会自动报错了。 类型检查主要还是防止 typo 以及写代码更方便一些比如说 我们项目的数据都是强定形的所以对我们项目来说使用 TS 的优势绝对比使用 JS 多……尤其是有些 entity 会有一百多个 attributes这时候如果没有一些智能提示或者是类型检查报错都得掉一堆头发
是的真的发生过后来发现就因为是 typo 所以拿不到值……还有就是后端改了一些数据类型然后前端没有在所有的组件中全部更新导致有些页面出现问题有些事正常的。也就是那时候我们决定要落实 TS 的实现虽然到最后只有我一个人在认真想怎么重构猪队友都在用 any……痛苦……