ZhenHe17 / blog

个人博客,希望能让各位看官有所收获,喜欢可以 star || watch ^_^ 🎉

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TypeScript 各个击破

ZhenHe17 opened this issue · comments

Type 和 Interface 的区别

本节摘自 Typescript: Interfaces vs Types

1. 对于对象和函数

type 和 interface 都可以用来定义对象和函数的类型,区别是语法不同

Interface

interface Point {
  x: number;
  y: number;
}

interface SetPoint {
  (x: number, y: number): void;
}

Type

type Point = {
  x: number;
  y: number;
};

type SetPoint = (x: number, y: number) => void;

2. 对于其他类型

相比 interface,type 还可以用于定义 原始类型、联合类型和元组。

// primitive 原始类型
type Name = string;

// object 对象
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };

// union 联合类型
type PartialPoint = PartialPointX | PartialPointY;

// tuple 元组
type Data = [number, string];

3. 继承

两者都可以被继承,只是语法不同。并且 type 可以继承 interface,interface 也可以继承 type。

// Interface 继承 interface
interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }

// type 继承 type
type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };

// Interface 继承 type
type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }

// type 继承 interface
interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };

4. 实现

类实现 interface 或者 type 用的是一样的语法,但是类不能实现一个联合类型的type。

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; };

// 错误的代码: 不能实现联合类型
class SomePartialPoint implements PartialPoint {
  x: 1;
  y: 2;
}

5. 合并声明

不同于 type,interface 可以声明多次,多次声明同一个 interface 会将他们合并。

// 声明了两次 Point 最终等同于:
// interface Point { x: number; y: number; }
interface Point { x: number; }
interface Point { y: number; }

const point: Point = { x: 1, y: 2 };

泛型

先看看使用泛型的语法:

function identity<T>(arg: T): T {
    return arg;
}

我们给identity添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了 T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。 这允许我们跟踪函数里使用的类型的信息。

可以看出,泛型实际上是用类型变量记录了传入的类型。每次传入不同类型的参数,其类型也得以保存。下面是官方文档里比较复杂的例子:

// 一个更高级的例子,使用原型属性推断并约束构造函数与类实例的关系。
class BeeKeeper {
    hasMask: boolean;
}

class ZooKeeper {
    nametag: string;
}

class Animal {
    numLegs: number;
}

class Bee extends Animal {
    keeper: BeeKeeper;
}

class Lion extends Animal {
    keeper: ZooKeeper;
}

function createInstance<A extends Animal>(c: new () => A): A {
    return new c();
}

createInstance(Lion).keeper.nametag;  // typechecks!
createInstance(Bee).keeper.hasMask;   // typechecks!

在 React 里使用 TS

用 TS 开发 React 时先要注意以下几点:

摘自深入理解 TypeScript

  • 使用文件后缀 .tsx(替代 .ts);
  • 在你的 tsconfig.json 配置文件的 compilerOptions 里设置选项 "jsx": "react";
  • 在你的项目里为 JSX 和 React 安装声明文件:npm i -D @types/react @types/react-dom;
  • 导入 react 到你的 .tsx 文件(import * as React from 'react')。

定义 React 组件

用类型 React.FunctionComponent<Props> 定义函数式组件:

type Props = {
  foo: string;
};

const MyComponent: React.FunctionComponent<Props> = props => {
  return <span>{props.foo}</span>;
};

<MyComponent foo="bar" />;

用类型 React.Component<Props,State> 定义类组件:

type Props = {
  foo: string;
};

class MyComponent extends React.Component<Props, {}> {
  render() {
    return <span>{this.props.foo}</span>;
  }
}

<MyComponent foo="bar" />;

用类型 React.ReactNode 定义可渲染的 React 内容:

type Props = {
  header: React.ReactNode;
  body: React.ReactNode;
};

class MyComonent extends React.Component<Props, {}> {
  render() {
    return (
      <div>
        {this.props.header}
        {this.props.body}
      </div>
    );
  }
}

<MyComponent header={<h1>Header</h1>} body={<i>body</i>} />

Hooks

useState

const [user, setUser] = React.useState<IUser | null>(null);

useRef

const ref2 = useRef<HTMLElement | null>(null);