TypeScript 各个击破
ZhenHe17 opened this issue · comments
GeShengming commented
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 时先要注意以下几点:
- 使用文件后缀 .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);