类型体操系列之实现Pick

大家好,我是初心,本篇是我坚持原创文章的第02期文章,如有错误,欢迎指正👏🏻

TS现状

介绍类型体操之前,容我讲个笑话,其实我一直在内卷TypeScript,却未尝试过项目实战,学了忘,忘了又学,一直循环;

后面无意发现了TS有类型体操,预期是想通过类型体操深入学习TS,打破目前困局。

什么是类型体操

那么什么是类型体操呢,类型体操来源 type-challenges 项目,其意在于更好的了解 TS 的类型系统,编写自己的类型工具,也有种只是单纯的享受挑战的乐趣!

type-challenges 的高质量类型可以提高项目的可维护性并避免一些潜在的漏洞。

知道了什么是类型体操,让我们正式开始吧。

题目介绍

实现 Pick

实现 TS 内置的 Pick<T, K>,但不可以使用它。

从类型 T 中选择出属性 K ,构造成一个新的类型

例如:

// 通过interface 定义了 Todo
interface Todo {
  title: string
  description: string
  completed: boolean
}

// 挑选出 title 和 completed
type TodoPreview = MyPick<Todo, 'title' | 'completed'>

const todo: TodoPreview = {
    title: '云层上的光',
    completed: false,
}

例子中interface定义了三个属性并定义了类型,MyPick从中挑选出 titlecompleted,这样 todo 声明的变量就必须是titlecompleted且类型分别是 字符串和布尔类型。

解题思路

熟悉Pick的童鞋对于这道题简直就是so一贼,不熟悉的童鞋也不要紧,Pick其实是 TS 内置方法,Pick的作用就是从一个对象中挑选需要的字段出来,比如从Todo里面只取出titlecompleted

在没有实现 Pick我们可以这样处理,重新声明一个新的类型

interface TodoPreviewType{
	title: string
  completed: boolean
}

这样做的好处确实可以解决这个问题,但是类型体操是让我们实现MyPick

MyPick实现

讲实话,初次接触类型体操,即使我有学习过TS可是还是做不出来,所以我们看看Issues的实现

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

短短的3行代码就实现了TS内置的Pick,简直是不可思议。

TS中keyof、extends、in原理

首先我们看看上文中keyofextendsin在TS中分别代表着什么含义?

keyof原理

TS 中的keyof的作用等价于 JS 中的Object.keys

// keyof
interface Person {
    name: string;
    age: number;
    gender: string;
}
// 此时的 P 就是一个联合类型
type P = keyof Person; // "name" | "age" | "gender"
extends原理

TS 中的extends有2个作用,第1个是继承 第2个是判断

// 第一种 继承
interface Person{
  name: string;
  age: number;
}

// A 继承了 Person 所有的类型
interface A extends Person{
  gender: string;
}

// 第二种 判断
interface B{
  name: string;
}
// 判断 B 是否 >= Person 也就是说 B的类型必须要多余或者等于  Person 才会是 true
type b = B extends Person ? true: false;// b ===  false
// 判断 1 是否是 number 类型
type isNnumber = 1 extends number ? true : false;
in原理

TS 中 in 其实和 JS 中的 in 用法一致,作用类似JS中的for…in或者for…of

MyPick实现原理

// MyPick实现原理
type MyPick<T, K extends keyof T> = {
    [P in K]: T[P];
};
  • 目光聚集在泛型中 <T, K extends keyof T> 此时的T代表的是谁呢?K 又代表的谁呢
  • 在使用中我们可以看到type TodoPreview = MyPick<Todo, 'title' | 'completed'>
  • 显而易见 T 其实就是 Todo。 K的话其实就是联合类型 ‘title’ | ‘completed’
  • 那么 k extends keyof T 检测 K是否符合 Todo 的类型
  • [P in K]: T[P]左边为循环,其中P就是循环的key,K则是联合类型(title | completed) 解析起来就是 [key in (‘title’ | ‘completed’)] : Todo[key]
  • 至此MyPick就算结束了。

总结

Pick 从一个对象中挑选需要的字段出来,挑选出来的字段取决于第二个参数。

### 创建描述接口体操比赛系统的UML图 #### UML 类图的设计思路 为了构建一个用于描述接口体操比赛的系统,可以采用面向对象分析方法来定义主要实体及其关系。在此背景下,类图能够清晰展示不同角色之间的关联以及它们各自的责任。 1. **识别核心概念** - `Participant`:参赛者信息,包括姓名、年龄等属性。 - `Judge`:裁判员负责评分,具有打分功能。 - `Routine`:一套完整的表演动作序列,属于某个特定项目的一部分。 - `Score`:记录每次评判的结果。 2. **建立继承结构** 考虑到可能存在多种类型的选手(成人组/儿童组),可以通过让子类继承自基类的方式来简化模型设计[^1]: ```mermaid classDiagram class Participant{ <<abstract>> +String name +int age +void perform() } Adult --> |is a| Participant Child --> |is a| Participant class Judge { +float scorePerformance(Participant p) } Routine <|-- GymnasticsRoutine Score --|> PerformanceEvaluation ``` 3. **引入接口表达复杂行为逻辑** 针对具体表现形式不同的情况,比如自由体操与其他专项技能的区别,可利用接口机制实现多态性支持。这里定义了一个名为`IRoutineEvaluator` 的接口,它规定了评估标准而不限制其实现细节。 4. **处理交互过程中的消息传递** 除了静态的对象间联系外,还需要考虑动态方面——即各组件之间是如何协作完成整个流程的。这涉及到消息发送与接收的过程建模,在此不展开讨论,但在实际应用中非常重要。 --- #### 绘制活动图以展现业务流 如果更关注于描绘事件发生的顺序而非参与者间的结构性质,则可以选择绘制活动图。这类图表有助于说明从报名到最后成绩公布期间的关键步骤。 1. 初始状态设定为“等待注册”,之后进入循环直到所有运动员都完成了登记; 2. 接着按预定计划依次安排每位选手出场并接受评审团点评; 3. 所有轮次结束后计算总得分,并依据排名颁发奖项; 以下是简单的MermaidJS语法表示法: ```mermaid graph TD; A[等待注册] --> B{还有未注册?}; B -- 是 --> C[继续注册]; B -- 否 --> D[准备开场]; D --> E[逐一登场]; E --> F[评委打分]; F --> G[统计分数]; G --> H[结束比赛]; ``` 通过上述两种方式相结合,既可以从宏观角度把握整体框架布局,又能聚焦局部深入探究内部运作原理。值得注意的是,以上仅提供了一种可能的设计方案,实际情况需根据具体需求灵活调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值