задний план
Недавно я просматривал исходный код antd, а также сам изучаю синтаксис и использование машинописного текста, а затем я собираюсь привлечь своих младших школьников и учителей для создания музыкального проигрывателя в качестве практики машинописного текста. наступить на яму;
Тогда я не ожидал, что попаду в большую яму в самом начале проекта — в процессе построения проекта react-redux, следующий контент — запись того, как я выбрался из этой глубокой ямы.
Начинать? не могу даже начать
Он попал в яму уже после создания проекта. . .
Создать проект
Процесс создания проекта очень прост, вы можете обратиться к этой статье, которую я написал ранеестатья
Начните карабкаться по яме с mapStateToProps&mapDispatchToProps
Я был не очень знаком с машинописным текстом в начале, поэтому мой первый редьюсер, действие, константа, файлы все заканчивались на .js, только код компонента заканчивался на .tsx, а затем я начал следить за процессом обработки состояния в хранилище mapStateToProps и действия mapDispatchToProps, кто бы мог подумать, что это будет начало кошмара, сначала я написал такой код:
import { bindActionCreators } from 'redux';
function mapStateToProps(state: {}) {
return {
player: state.PlayerStore,
};
}
function mapDispatchToProps(dispatch: Function) {
return {
playerActions: bindActionCreators(actions, dispatch)
};
}
然后就开始报错了。 . .
После долгих метаний я изменил код на этот и смог пройти тест
import { bindActionCreators, Dispatch } from 'redux';
function mapStateToProps(state: { PlayerStore: object }) {
return {
player: state.PlayerStore,
};
}
function mapDispatchToProps(dispatch: Dispatch<{}>) {
return {
playerActions: bindActionCreators<{}>(actions, dispatch)
};
}
Тип утверждения компонента реакции восхождения на яму
interface PlayerPropsClass {
player: PlayerStateTypes;
playerActions: actions.PlayerActionsTypes;
}
class Player extends React.Component<PlayerPropsClass, {}> {
constructor(props: object) {
super(props as PlayerPropsClass);
this.state = {};
}
addOne = (num: number) => this.props.playerActions.count(num);
subtractOne = (num: number) => this.props.playerActions.subtract(num);
render() {
const { countNumber } = this.props.player.toJS();
return (
<div className="player">
<span>{countNumber}</span>
<button onClick={() => this.addOne(countNumber as number)}>点击+1</button>
<button onClick={() => this.subtractOne(countNumber as number)}>点击-1</button>
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Player as any);
Вот сообщение об ошибке (Player as any)
[tslint] Type declaration of 'any' loses type-safety. Consider replacing it with a more precise type, the empty type ('{}'), or suppress this occurrence. (no-any)
Затем я изменился на
export default connect(mapStateToProps, mapDispatchToProps)(Player as {});
все еще ошибка
[ts]
类型“{}”的参数不能赋给类型“ComponentType<{ player: object; } & { playerActions: {}; }>”的参数。
不能将类型“{}”分配给类型“StatelessComponent<{ player: object; } & { playerActions: {}; }>”。
类型“{}”提供的内容与签名“(props: { player: object; } & { playerActions: {}; } & { children?: ReactNode; }, context?: any): ReactElement<any> | null”不匹配。
Ничего себе, мой разум взрывается, я не знаю, как написать это утверждение. . . Тут я вспомнил пример от antd, который писалReact.ReactElement
, а затем случайно нашел в Интернете, что в Node_Modules есть папка @type в Node_Modules, которые находятся на типоре соответствующего типа в пакете узла, поэтому я следовал по этому путиnode_modules/@types/react/index.d.ts
,Наконец-то нашелReact.ComponentType<T>
, в этом файле много типов, если хотите узнать больше, можете посмотреть сами
export default connect(mapStateToProps, mapDispatchToProps)(Player as React.ComponentType<PlayerPropsClass>);
Восхождение на яму и редуктор
С вышеперечисленным опытом, плюсздесьПочитав немного кода, я решил изменить действия и редукторы на файлы, оканчивающиеся на ts;
-
src/reducers/index.ts
import { combineReducers, createStore } from 'redux'; import PlayerStore from '../containers/Player/reducer'; // 这个是用来使用到mapStateToProps函数的地方给state进行类型检测的 export interface AppStoreType { PlayerStore: object; } const rootReducer = combineReducers({ PlayerStore, }); export default () => { return createStore(rootReducer); };
-
containers/Demo/reducer.ts
import * as PlayerTypes from './constant'; import { fromJS } from 'immutable'; // 由于使用到immutable,state上面就会使用到immutable的函数,所以需要将其也做成类型检测 import { ImmutableFuncType } from '../../constant'; interface ActionType { type: string; countNumber?: number; } interface StoreType { countNumber: number; } // 把当前容器的state组,然后抛出提供使用 export type PlayerStateTypes = StoreType & ImmutableFuncType; const PlayerStore: PlayerStateTypes = fromJS({ countNumber: 0, }); export default (state = PlayerStore, action: ActionType) => { switch (action.type) { case PlayerTypes.COUNT: return state.update('countNumber', () => fromJS(action.countNumber)); default: return state; } };
-
containers/Demo/action.ts
import * as PlayerTypes from './constant'; export const count = (num: number) => ({ type: PlayerTypes.COUNT, countNumber: num + 1, }); export const subtract = (num: number) => ({ type: PlayerTypes.COUNT, countNumber: num - 1, }); // 抛出actions函数的类型以供mapDispatchToProps使用 export interface PlayerActionsTypes { count: Function; subtract: Function; }
-
containers/Demo/index.tsx
import * as React from 'react'; import './style.css'; import { connect } from 'react-redux'; import { bindActionCreators, Dispatch } from 'redux'; import * as actions from './action'; import { PlayerStateTypes } from './reducer'; import { AppStoreType } from '../../reducers'; interface PlayerPropsClass { player: PlayerStateTypes; playerActions: actions.PlayerActionsTypes; } function mapStateToProps(state: AppStoreType) { return { player: state.PlayerStore, }; } function mapDispatchToProps(dispatch: Dispatch<{}>) { return { playerActions: bindActionCreators<{}>(actions, dispatch) }; } class Player extends React.Component<PlayerPropsClass, {}> { constructor(props: object) { super(props as PlayerPropsClass); this.state = {}; } addOne = (num: number) => this.props.playerActions.count(num); subtractOne = (num: number) => this.props.playerActions.subtract(num); render() { const { countNumber } = this.props.player.toJS(); return ( <div className="player"> <span>{countNumber}</span> <button onClick={() => this.addOne(countNumber as number)}>点击+1</button> <button onClick={() => this.subtractOne(countNumber as number)}>点击-1</button> </div> ); } } export default connect(mapStateToProps, mapDispatchToProps)(Player as React.ComponentType<PlayerPropsClass>);
конец
Благодаря этому небольшому упражнению я действительно ощутил преимущества машинописного текста, то есть об ошибках сообщается во время компиляции, и можно узнать причину ошибки, нет необходимости искать точку ошибки после завершения компиляции, что действительно экономит много времени, особенно он очень удобен для обработки неопределенных и нулевых значений в коде JavaScript. . В общем, писать так легко. Ахахахаха~~~