React TypeScript项目语法

1,128 阅读5分钟

有状态组件开发

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的相同点和不同点

  1. 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 不支持。