pc-live

image.png
image.pngimage.png
image.png

  1. import {Anchor, Union} from 'utils/type';
  2. # React.FC<{info: Anchor}>
  3. const AnchorInfo: React.FC<{info: Anchor}> = ({info}) => {}
  4. interface ColumnItem {
  5. [key: string]: string | undefined;
  6. name: string;
  7. introduction?: string;
  8. city?: string;
  9. phone?: string;
  10. userName?: string;
  11. }
  12. interface CardType {
  13. title: string;
  14. columns: ColumnItem;
  15. dataSource: any;
  16. styletype: any;
  17. }
  18. const Card: React.FC<CardType> = ({title, columns, dataSource, styletype}) => {}
  19. <Card title="个人信息" columns={columns1} dataSource={info} styletype={'anchor'} />
  1. useState<类型>(默认值)

image.png
image.png
image.png
image.png
image.png

  1. onOk: (params: any) => void;
  2. onOk: (参数:类型) => 返回值
  3. # 参数为对象 {timeRange, anchorUid},对象的各自类型指定
  4. onOk: ({timeRange, anchorUid}: {timeRange: string, anchorUid: string}) => void;

泛型

详见泛型

ts开发思维

image.png
想着没有ts类似约束的代码,我们都是在方法定义那块针对穿漏的情况做各种兜底的处理

TS可以为你提供类似的各种逻辑约束,这种约束发生在编译时。
允许你在代码执行之前就能保证代码一定程度上遵循你设计好的约束条件

image.png

deepcopy函数,那其参数(复制的对象)和返回值(复制的结果)的类型是相同的,类型无所谓
此时的约束状态就是:输入类型===输出类型
使用any只能说明类型任意,不满足这一约束
所以引入了 泛型:

有时你的约束不是不变的、它有变动的部分,也有不变的部分,类型可以是变化的、但是其内部的推断关系则是不变的,这种更抽象的不变的约束则要借助范型(Generics)

  1. function deepcopy(something: number): number;
  2. ...
  3. function deepcopy(something: any): any;
  4. // any的情况参数和返回值缺少必须是相同类型的约束逻辑
  5. function deepcopy<T>(something: T): T;
  6. // 使用泛型来约束

image.png

好的实践

减少重复的声明

接口合并

interface PointWithLength extends Point{
type PointWithLength = Point & {size: number};
image.png

image.png
image.png

type vs interface

  1. # type 定义基础的
  2. # interface 元素 引用最基础的type对象
  3. export type BBox = {
  4. x: number;
  5. y: number;
  6. minX?: number;
  7. };
  8. export interface IElement extends IBase {
  9. /**
  10. * 获取图形元素相对画布的包围盒,会计算从顶层到当前的 matrix
  11. * @returns {BBox} 包围盒
  12. */
  13. getCanvasBBox(): BBox;
  14. }
  15. 有哪些是type定义的?
  16. ShapeCfg
  17. PointBBox

接口

  1. export interface ICanvas extends IContainer {
  2. /**
  3. * 将 canvas 坐标转换成窗口坐标
  4. * @param {number} x canvas 上的 x 坐标
  5. * @param {number} y canvas 上的 y 坐标
  6. * @returns {object} 窗口坐标
  7. */
  8. getClientByPoint(x: number, y: number): Point;
  9. }
  10. # 接口里的方法返回某个带方法的元素,这个元素就是用接口定义的
  11. export interface IElement extends IBase {
  12. /**
  13. * 获取所属的 Canvas
  14. * @return {ICanvas} Canvas 对象
  15. */
  16. getCanvas(): ICanvas;
  17. }
相同点 都可以描述一个对象或者函数
都允许拓展(extends)
type
>
interface
type 声明的方式可以定义组合类型,交叉类型,原始类型
// 联合类型
interface Dog {
wong();
}
interface Cat {
miao();
}

type Pet = Dog | Cat
// 具体定义数组每个位置的类型
type PetList = [Dog, Pet]
type StringOrNumber = string | number;
type Text = string | { text: string };
type NameLookup = Dictionary;
type Callback = (data: T) => void;
type Pair = [T, T];
type Coordinates = Pair;
type Tree = T | { left: Tree, right: Tree };
interface
>
type
interface 能够声明合并
interface User {
name: string
age: number
}

interface User {
sex: string
}

/
User 接口为 {
name: string
age: number
sex: string
}
/
一个函数,如果想使用函数名.值的方式,只能 interface

巧用 Typescript

参考:巧用1 巧用2

类型方向是:从子到父,慢慢堆积庞大
类与函数的区别?当类与类之间用了同样的逻辑,则把这个handler抽象为公共方法,而不是类之间进行调用传递

子需要使用父的方法?子通知父的方法去调用更新如何写?
父.update的方法 传递给子(在实例化的时候:new constructor时
子发生事件后,调用父传给子的方法,实现通知父
『类的构造函数入参类型,是另一个类的某个方法』

子依赖父的方法

  1. interface ChildProps {
  2. updateHeader: Parent['updateHeader'];
  3. // updateHeader: (title: string, subTitle: string) => void;
  4. }
  5. class Child extends React.PureComponent<ChildProps> {
  6. private onClick = () => {
  7. this.props.updateHeader('Hello', 'Typescript');
  8. };
  9. render() {
  10. return <button onClick={this.onClick}>Go</button>;
  11. }
  12. }
  13. class Parent extends React.PureComponent {
  14. private updateHeader = (title: string, subTitle: string) => {
  15. // Do it.
  16. };
  17. render() {
  18. return <Child updateHeader={this.updateHeader}/>; # 传给子
  19. }
  20. }

defaultOpts:Partial\

1、Partial:部分的意思

  1. const mergeOptions = (options: Opt, patch: Partial<Opt>) {
  2. return { ...options, ...patch };
  3. }
  4. class MyComponent extends React.PureComponent<Props> {
  5. defaultProps: Partial<Props> = {};
  6. }

2、当一个 interface 总有一个字面量初始值时,可以考虑这种写法以减少重复代码。

  1. const defaultOption = {
  2. timeout: 500
  3. }
  4. # 根据初始化的值 来得到type
  5. type Opt = typeof defaultOption
  6. 正常写法:
  7. interface Opt {
  8. timeout: number
  9. }
  10. const defaultOption: Opt = {
  11. timeout: 500
  12. }

二者取一的功能

Dinner 要么有 fish 要么有 bear 。

  1. // Awesome!
  2. type Dinner2 = {
  3. fish: number,
  4. } | {
  5. bear: number,
  6. }
  7. 而不是
  8. // Not good.
  9. interface Dinner1 {
  10. fish?: number,
  11. bear?: number,
  12. }

Record:保证映射完整

  1. type AnimalType = 'cat' | 'dog' | 'frog';
  2. interface AnimalDescription { name: string, icon: string }
  3. const AnimalMap: Record<AnimalType, AnimalDescription> = {
  4. // key: 是对应的AnimalType
  5. cat: { name: '猫', icon: ' '},
  6. dog: { name: '狗', icon: ' ' },
  7. forg: { name: '蛙', icon: ' ' }, // Hey!
  8. };

参考资料

掘金-Typescript代码整洁之道
知乎问题-如何培养 TypeScript 开发思维?
帮助建立ts思维的很多例子—TypeScript 疑难杂症
沈毅大佬-TypeScript 类型编写指南(上篇) | 下篇

空了再看:
TS 学习总结:编译选项 && 类型相关技巧

强烈推荐阅读 ->Conditional types in TypeScript - David Sheldrick写的很通俗易懂,幽默风趣。 推荐阅读 ->Conditional Types in TypeScript - Marius Schulz写的很详细,比官方文档总结的更好。