:::tip TypeScript 是有类型定义的 JS 的超集,包括 ES5、ES5+ 和其他一些诸如泛型、类型定义、命名空间等特征的集合,为了大规模 JS 应用而生。 ::::
相关链接:
npm install -g create-react-app
使用create-react-app创建TypeScript项目
create-react-app my-app --scripts-version=react-scripts-ts
npm run dev
我们将创建一个有状态组件,并定义interface接口Props与State应用到组件上.
:::tip 在只有state而没有props的情况下,props的位置可以用{}或者object占位,这两个值都表示有效的空对象。 ::::
// /src/components/Hello.tsx
import * as React from "react";
export interface Props {
name: string;
enthusiasmLevel?: number;
}
interface State {
currentEnthusiasm: number;
}
class Hello extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { currentEnthusiasm: props.enthusiasmLevel || 1 };
}
onIncrement = () => this.updateEnthusiasm(this.state.currentEnthusiasm + 1);
onDecrement = () => this.updateEnthusiasm(this.state.currentEnthusiasm - 1);
render() {
const { name } = this.props;
if (this.state.currentEnthusiasm <= 0) {
throw new Error('你可以更热情一点. :D');
}
return (
<div className="hello">
<div className="greeting">
Hello {name + getExclamationMarks(this.state.currentEnthusiasm)}
</div>
<button onClick={this.onDecrement}>-</button>
<button onClick={this.onIncrement}>+</button>
</div>
);
}
updateEnthusiasm(currentEnthusiasm: number) {
this.setState({ currentEnthusiasm });
}
}
export default Hello;
function getExclamationMarks(numChars: number) {
return Array(numChars + 1).join('!');
}
npm install -S redux react-redux @types/react-redux
首先,需要给我们的Redux store定义一个interface
// src/types/index.tsx
export interface StoreState{
name:string,
enthusiaimLevel:number
}
所有的actions类型可以用一种const & type的模式来定义 注意必须导出对应的type
// src/constants/index.tsx
export const INCREMENT_ENTHUSIASM = "INCREMENT_ENTHUSIASM";
export type INCREMENT_ENTHUSIASM = typeof INCREMENT_ENTHUSIASM;
export const DECREMENT_ENTHUSIASM = "DECREMENT_ENTHUSIASM";
export type DECREMENT_ENTHUSIASM = typeof DECREMENT_ENTHUSIASM;
这种const/type所组成的对象现在可以在src/actions/index.tsx文件中进行导入了,下面我们来定义action interface以及action自身并指明类型
// src/constants/actions/index.tsx
import * as constants from '../constants';
export interface IncrementEnthusiasm {
type: constants.INCREMENT_ENTHUSIASM;
}
export interface DecrementEnthusiasm {
type: constants.DECREMENT_ENTHUSIASM;
}
/**typescript1.4版本后引入联合类型 联合类型允许我们将两种或两种以上的类型合并为一个类型
可以简化在reducer中指定action type类型的方式**/
export type EnthusiasmAction = IncrementEnthusiasm | DecrementEnthusiasm;
export function incrementEnthusiasm(): IncrementEnthusiasm {
return {
type: constants.INCREMENT_ENTHUSIASM
};
}
export function decrementEnthusiasm(): DecrementEnthusiasm {
return {
type: constants.DECREMENT_ENTHUSIASM
};
}
// src/reducer/index.tsx
import { EnthusiasmAction } from '../actions';
import { StoreState } from '../types/index';
import { INCREMENT_ENTHUSIASM, DECREMENT_ENTHUSIASM } from '../constants/index';
export function enthusiasm(
state: StoreState,
action: EnthusiasmAction
): StoreState {
switch (action.type) {
case INCREMENT_ENTHUSIASM:
return { ...state, enthusiaimLevel: state.enthusiaimLevel + 1 };
case DECREMENT_ENTHUSIASM:
return { ...state, enthusiaimLevel: Math.max(1, state.enthusiaimLevel - 1) };
}
return state;
}
// src/components/Hello.tsx
import * as React from 'react';
import * as actions from '../actions';
import { StoreState } from '../types/index';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
export interface Props {
name?: string;
enthusiaimLevel?: number;
onIncrement?: () => void;
onDecrement?: () => void;
}
export interface State {
currentEnthusiasm: number;
}
class Hello extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
currentEnthusiasm: props.enthusiaimLevel || 1
};
}
updateEnthusiasm(currentEnthusiasm: number) {
this.setState({
currentEnthusiasm
});
}
render() {
const { name } = this.props;
return (
<div className="Hellon">
<div className="greeting">Hello {name + getExclamationMarks(this.props.enthusiaimLevel || 0)}</div>
<button onClick={this.props.onDecrement}>-</button>
<button onClick={this.props.onIncrement}>+</button>
</div>
);
}
}
/**
*
* @param numChars 等级
*/
function getExclamationMarks(numChars: number) {
return Array(numChars + 1).join('!');
}
function mapStateToProps({ enthusiaimLevel, name }: StoreState) {
return {
enthusiaimLevel,
name
};
}
function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
return {
onIncrement: () => dispatch(actions.incrementEnthusiasm()),
onDecrement: () => dispatch(actions.decrementEnthusiasm())
};
}
export default connect(mapStateToProps,mapDispatchToProps)(Hello);
改写index.tsx,创建一个store,并设置初始默认值
// src/index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import './index.css';
import registerServiceWorker from './registerServiceWorker';
import { createStore } from 'redux';
import { EnthusiasmAction } from './actions/index';
import { enthusiasm } from './reducer/index';
import { StoreState } from './types/index';
import { Provider } from 'react-redux';
import Hello from './components/Hello';
const store = createStore<StoreState, EnthusiasmAction, any, any>(enthusiasm, {
enthusiaimLevel: 1,
name: 'TypeScript'
});
ReactDOM.render(
<Provider store={store}>
<Hello />
</Provider>,
document.getElementById('root') as HTMLElement
);
registerServiceWorker();