有状态组件开发
interface IProps {
color: string,
size?: string,
}
interface IState {
count: number,
}
class App extends React.PureComponent<IProps, IState> {
readonly state: Readonly<IState> = {
count: 1,
}
render () {
return (
<div>Hello world</div>
)
}
componentDidMount () {
this.state.count = 2
}
}
export default App
无状态组件开发
在 React 的声明文件中 已经定义了一个 SFC 类型,使用这个类型可以避免我们重复定义 children、 propTypes、 contextTypes、 defaultProps、displayName 的类型。
使用 SFC 进行无状态组件开发。
import { SFC } from 'react'
import { MouseEvent } from 'react'
import * as React from 'react'
interface IProps {
onClick (event: MouseEvent<HTMLDivElement>): void,
}
const Button: SFC<IProps> = ({onClick, children}) => {
return (
<div onClick={onClick}>
{ children }
</div>
)
}
export default Button
React.FC 用法
使用函数式组件时需要将组件申明为React.FC类型,也就是Functional Component的意思,另外props需要申明各个参数的类型,然后通过泛型传递给React.FC。
interface DraggableLayerProps {
children?: React.ReactElement;
titleName?: string;
visible?: boolean;
onClose?: () => void;
}
const DraggableLayer: React.FC<DraggableLayerProps> = props => <Component />
export default DraggableLayer
可以支持children的传入,即使在我们的类型中并没有定义它,在定义user的时候没有传入children,但是在User组件中也是可以获取的到children
export const User:React.FC<UserInfo> = ({ name, age, children }) => {
return (
<div className="User">
<p>{ name }</p>
<p>{ age }</p>
<div>
{ children }
</div>
</div>
)
}
const user = <User name='vortesnail' age={25}>I am children text!</User>
我们也并不需要把所有参数都显示地解构:
export const User:React.FC<UserInfo> = (props) => {
return (
<div className="User">
<p>{ props.name }</p>
<p>{ props.age }</p>
<div>
{ /* 仍可以拿到 children */ }
{ props.children }
</div>
</div>
)
}
const user = <User name='vortesnail' age={25}>I am children text!</User>
Promise 类型
Promise 是一个泛型类型,T 泛型变量用于确定使用 then 方法时接收的第一个回调函数(onfulfilled)的参数类型。
interface IResponse<T> {
message: string,
result: T,
success: boolean,
}
async function getResponse (): Promise<IResponse<number[]>> {
return {
message: '获取成功',
result: [1, 2, 3],
success: true,
}
}
getResponse()
.then(response => {
console.log(response.result)
})
受控组件
- 对于input组件onChange中的事件
private updateValue(e: React.ChangeEvent<HTMLInputElement>) {
this.setState({ itemText: e.target.value })
}
- 提交表单
private handleSubmit(e: React.FormEvent<HTMLFormElement>) { }
Partial的作用就是将类型的属性全部变成可选的,比如在属性后加 ?
const todoInputDefaultProps = {
inputSetting: {
maxlength: 20,
placeholder: '请输入tood'
}
}
type Props = {
handleSubmit: (value: string)=> void,
children:React.ReactNode
} & Partial<typeof todoInputDefaultProps>
TypeScript 中 interface 和 type 使用区别
interface:接口
1.1可选属性
```
interface Config {
color?: string;
}
```
1.2只读属性
```
interface Point {
readonly x: number;
}
```
1.3多余属性检查,防止使用不属于接口的属性
```
interface Preson {
name: string;
age?: number;
}
let p1:Person = {name: '小明'} // 正确
let p2:Person = {name: '小明', age: 18, sex: '男'}; // 报错
// 绕过:多余属性不报错
// 方式1
let p = {name: '小明', age: 18, sex: '男'};
let p3 = p;
// 方式2
interface Preson {
name: string;
age?: number;
[propName: string]: any
}
let p4 = {name: '小明', age: 18, sex: '男'};
```
1.4函数类型
```
interface SearchFunc {
(source: string, subString: string): boolean;
}
```
1.5索引类型: 针对数组
```
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"]
```
1.6类型:类类型接口
```
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
```
1.7继承多个接口
```
interface Cat {
eat: string;
}
interface Dog {
pull: string;
}
interface Zoom extends Cat, Dog {
play: string;
}
let zoom = <Zoom>{};zoom.eat= `疯狂吃`;zoom.pull= `疯狂拉`;zoom.play= `疯狂撸`
```
type:类型别名
type 会给一个类型起个新名字。 type 有时和 interface 很像,但是可以作用于原始值(基本类型),联合类型,元组以及其它任何你需要手写的类型。
type Name = string; // 基本类型
type NameFun = () => string; // 函数
type NameOrRFun = Name | NameFun; // 联合类型
function getName(n: NameOrRFun): Name { if (typeof n === 'string') {
return n;
}
return n();
}
起别名不会新建一个类型 - 它创建了一个新 名字来引用那个类型。给基本类型起别名通常没什么用,尽管可以做为文档的一种形式使用。
同接口一样,类型别名也可以是泛型 - 我们可以添加类型参数并且在别名声明的右侧传入:
type Container<T> = { value: T };
也可以使用类型别名来在属性里引用自己:
type TreeNode<T> = {
value: T;
left: TreeNode<T>; right: TreeNode<T>;
}
interface vs type的相同点和不同点
- Objects / Functions 两者都可以用来描述对象或函数的类型,但是语法不同。
Interface
interface Point {
x: number;
y: number;
}
interface SetPoint {
(x: number, y: number): void;
}
Type alias
type Point = {
x: number;
y: number;
};
type SetPoint = (x: number, y: number) => void;
Other Types
与接口不同,类型别名还可以用于其他类型,如基本类型(原始值)、联合类型、元组
// primitive
type Name = string;
// object
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };
// union
type PartialPoint = PartialPointX | PartialPointY;
// tuple
type Data = [number, string];
// dom
let div = document.createElement('div');
type B = typeof div;
Extend
两者都可以扩展,但是语法又有所不同。此外,请注意接口和类型别名不是互斥的。接口可以扩展类型别名,反之亦然。
接口继承接口
interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }
type继承type
type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };
接口继承type
type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }
type继承接口
interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };
class Implements
类可以以相同的方式实现接口或类型别名。但是请注意,类和接口被认为是静态的。因此,它们不能实现/扩展命名联合类型的类型别名。
interface Point {
x: number;
y: number;
}
class SomePoint implements Point {
x: 1;
y: 2;
}
type Point2 = {
x: number;
y: number;
};
class SomePoint2 implements Point2 {
x: 1;
y: 2;
}
type PartialPoint = { x: number; } | { y: number; };
// FIXME: can not implement a union type
class SomePartialPoint implements PartialPoint {
x: 1;
y: 2;
}
计算属性,生成映射类型
type 能使用 in 关键字生成映射类型,但 interface 不行。
语法与索引签名的语法类型,内部使用了 for .. in。 具有三个部分
- 类型变量 K,它会依次绑定到每个属性。
- 字符串字面量联合的 Keys,它包含了要迭代的属性名的集合。
- 属性的结果类型。
type Keys = "firstname" | "surname"
type DudeType = {
[key in Keys]: string
}
const test: DudeType = {
firstname: "Pawel",
surname: "Grzybek"
}
// 报错
//interface DudeType2 {
// [key in keys]: string
//}3.8. 其他细节
export default interface Config {
name: string
}
// export default type Config1 = {
// name: string
// }
// 会报错
type Config2 = {
name: string
}
export default Config2
interface 和 type 很像,很多场景,两者都能使用。但也有细微的差别
- 类型:对象、函数两者都适用,但是 type 可以用于基础类型、联合类型、元祖。
- 同名合并:interface 支持,type 不支持。
- 计算属性:type 支持, interface 不支持。