TypeScript + React
在使用 Typescript 时,React.Component 是一个通用类型 (也被写作 React.Component<PropType, StateType>),所以你实际上需要给它提供 prop 和 state(可选)的类型:
export default class Counter extends React.Component<Props, object> {
render() {
const { name, count = 1 } = this.props;
return (
<div>
Counter {name}: {count}
</div>
);
}
}
这里React.Component<Props, object>第一个是props的参数类型, 第二个是state的类型。因为我们暂时用不到state,所以简单放一个objcet类型即可。
无状态组件:
在@types/react中已经预定义一个类型type SFC<P>,它也是类型interface StatelessComponent<P>的一个别名,此外,它已经有预定义的children和其他(defaultProps、displayName等等…),所以我们不用每次都自己编写!
import React, { MouseEvent, SFC } from 'react';
type Props = { onClick(e: MouseEvent<HTMLElement>): void };
const Button: SFC<Props> = ({ onClick: handleClick, children }) => (
<button onClick={handleClick}>{children}</button>
);
使用TS写react组件,与es6的区别是props和state的定义:
interface IProps {
aProps: string;
bProps: string;
}
interface IState {
aState: string;
bState: string;
}
class App extends React.PureComponent<IProps, IState> {
state = {
aState: '',
bState: '',
};
}
React.ReactEventHandler<E>
const handleChange: React.ReactEventHandler<HTMLInputElement> = (ev) => { ... }
<input onChange={handleChange} ... />
React.MouseEvent<E> | React.KeyboardEvent<E> | React.TouchEvent<E> etc...
const handleChange = (ev: React.MouseEvent<HTMLDivElement>) => { ... }
<div onMouseMove={handleChange} ... />
React.CSSProperties
const styles: React.CSSProperties = { flexDirection: 'row', ...
const element = <div style={styles} ...
Stateful Component
import * as React from 'react';
export interface StatefulCounterProps {
label: string;
}
interface State {
readonly count: number;
}
export class StatefulCounter extends React.Component<StatefulCounterProps, State> {
readonly state: State = {
count: 0,
};
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
const { handleIncrement } = this;
const { label } = this.props;
const { count } = this.state;
return (
<div>
<span>{label}: {count} </span>
<button type="button" onClick={this.handleIncrement}>
{`Increment`}
</button>
</div>
);
}
}
Generic Components通用组件
import * as React from 'react';
export interface GenericListProps<T> {
items: T[];
itemRenderer: (item: T) => JSX.Element;
}
export class GenericList<T> extends React.Component<GenericListProps<T>, {}> {
render() {
const { items, itemRenderer } = this.props;
return (
<div>
{items.map(itemRenderer)}
</div>
);
}
}
Interface 和 type
编写库或第三方环境类型定义时,对于公共API总是使用Interface
考虑使用React Component Props和State的类型
interface 可以继承,type不可以
解构赋值的数据类型声明
function getStock() {
return {
name: 'bitcoin',
value: {
value1: 50000,
value2: 60000
}
}
}
const { name: code, value: { value2 } }: { name: string, value: {value2: number} } = getStock();
console.log(code);// bitcoin
console.log(value2)// 6000
关于函数参数默认值
// 参数默认值最好声明在最后面
function test(a: string='first', b: string, c: string = 'third') {
console.log(a)
console.log(b)
console.log(c)
}
test('', 'aaa');// '' aaa third
// 可选参数必须声明在必选参数的后面
function test(a: string='first', b?: string, c: string = 'third') {
console.log(a)
console.log(b.length);// Cannot read property 'length' of undefined
console.log(c)
}
test();//first 要记得处理可选参数的情况
非空断言标志符
const config = {
port: 8000
};
if (config) {
console.log(config.port);
}
// 有了 2.0 提供的 “非空断言标志符”,我们可以这么写了:
console.log(config!.port);
关于命名空间
//pre-compile
namespace Validation {
const lettersRegexp = /^[A-Za-z]+$/;
const numberRegexp = /^[0-9]+$/;
}
//post-compile
var Validation;
(function (Validation) {
var lettersRegexp = /^[A-Za-z]+$/;
var numberRegexp = /^[0-9]+$/;
})(Validation || (Validation = {}));
所以namespace也不过就是一个匿名函数的自执行而已,将namespace的名字作为其参数而已
Interface
TypeScript 一共提供 6 种 interface
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
interface CloudDictionary {
[index: number]: string;// 定义index为number,返回值为string
}
let clouds: CloudDictionary = {};
clouds[0] = 'aws';
要求 class 需具备哪些 public method 与 property 时,会使用 interface 特別定义。
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
Interface 只能定義 class 的 public 部分,無法定義其 private 與 protected 部分。
- Constructor interface
- Function interface
在 OOP,我們期望 class 該有哪些 public property 與 method,可使用 class interface 描述。
在 FP,我們會期望 function 該有哪些 signature,可使用 function interface 描述。
interface ILogistics {
(weight: number): number
}
class ShippingService {
calculateFee(weight: number, logistics: ILogistics): number {
return logistics(weight);
}
}
const shippingService = new ShippingService();
const fee = shippingService.calculateFee(10, weight => 100 * weight + 10);
console.log(fee); // 1010
对象的类型——接口Interface
接口名一般首字母大写。定义的变量比接口少/多了一些属性都是不允许的。
其实接口就是定义了一个对象有哪些属性,并且属性值是什么类型。如果一个函数返回了一个对象,那么可以用来限定函数返回值类型。
一个接口可以继承多个接口,创建出多个接口的合成接口。
接口通常会根据一个对象是否符合某种特定结构来进行类型检查。当转译成 JavaScript 时,接口会消失 – 它们唯一的目的是在开发阶段里起到辅助的作用。
如果接口需要在其他地方被使用,那么Interface需要export
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
这里,我们定义一个简单接口来对函数自变量进行类型检查:
// Here we define our Food interface, its properties, and their types.
interface Food {
name: string;
calories: number;
}
// We tell our function to expect an object that fulfills the Food interface.
// This way we know that the properties we need will always be available.
function speak(food: Food): void{
console.log("Our " + food.name + " has " + food.calories + " calories.");
}
// We define an object that has all of the properties the Food interface expects.
// Notice that types will be inferred automatically.
var ice_cream = {
name: "ice cream",
calories: 200
}
speak(ice_cream);
接口类型可以作为方法的参数类型,接口也可以定义方法的类型,和数组类型
interface FuncType {
(x: string, y: string): string; // 声明方法成员
}
let func1: FuncType;
func1 = function (prop1: string, prop2: string): string {// 方法参数名称不需要与接口成员的参数名称保持一致
return prop1 + ' ' + prop2;
}
interface ArrayType {
[index: number]: string; // 声明数组成员
}
let arr: ArrayType;
arr = ['Dog', 'Cat'];
TypeScript的接口支持继承与实现。类通过implements关键字继承接口,并实现接口成员。
interface Animal {
name: string;
eat(): void;
}
class Dog implements Animal {
name: string;
constructor(theName: string) {
this.name = theName;
}
eat() {
console.log(`${this.name} 吃狗粮。`)
}
}
let dog: Animal;
dog = new Dog('狗狗');
dog.eat();
可选属性
interface SquareConfig {
color?: string;
width?: number;
}
TypeScript + React
在使用 Typescript 时,React.Component 是一个通用类型 (也被写作
React.Component<PropType, StateType>),所以你实际上需要给它提供 prop 和 state(可选)的类型:这里
React.Component<Props, object>第一个是props的参数类型, 第二个是state的类型。因为我们暂时用不到state,所以简单放一个objcet类型即可。在
@types/react中已经预定义一个类型type SFC<P>,它也是类型interface StatelessComponent<P>的一个别名,此外,它已经有预定义的children和其他(defaultProps、displayName等等…),所以我们不用每次都自己编写!使用TS写react组件,与es6的区别是props和state的定义:
Interface 和 type
编写库或第三方环境类型定义时,对于公共API总是使用Interface
考虑使用React Component Props和State的类型
interface 可以继承,type不可以
解构赋值的数据类型声明
关于函数参数默认值
非空断言标志符
关于命名空间
所以namespace也不过就是一个匿名函数的自执行而已,将namespace的名字作为其参数而已
Interface
TypeScript 一共提供 6 种 interface
要求 class 需具备哪些 public method 与 property 时,会使用 interface 特別定义。
Interface 只能定義 class 的 public 部分,無法定義其 private 與 protected 部分。
在 OOP,我們期望 class 該有哪些 public property 與 method,可使用 class interface 描述。
在 FP,我們會期望 function 該有哪些 signature,可使用 function interface 描述。
对象的类型——接口Interface
接口名一般首字母大写。定义的变量比接口少/多了一些属性都是不允许的。
其实接口就是定义了一个对象有哪些属性,并且属性值是什么类型。如果一个函数返回了一个对象,那么可以用来限定函数返回值类型。
一个接口可以继承多个接口,创建出多个接口的合成接口。
接口通常会根据一个对象是否符合某种特定结构来进行类型检查。当转译成 JavaScript 时,接口会消失 – 它们唯一的目的是在开发阶段里起到辅助的作用。
如果接口需要在其他地方被使用,那么Interface需要export
这里,我们定义一个简单接口来对函数自变量进行类型检查:
接口类型可以作为方法的参数类型,接口也可以定义方法的类型,和数组类型
TypeScript的接口支持继承与实现。类通过implements关键字继承接口,并实现接口成员。