一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情。
前置知识
今日 【extreme - 8.getReadOnlyKeys】
在这之前需要掌握一点Ts基础知识,可以参考学习记录TypeScript学习记录-[数据类型]、TypeScript学习记录-[类和接口]、TypeScript学习记录-[枚举和泛型]、TypeScript学习记录-[类型别名、类型断言、声明文件]
二、题目分析
get-readonly-keys
实现泛型GetReadonlyKeys,该GetReadonlyKeys返回对象的只读键的并集。
type GetReadonlyKeys<T> = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<'title', GetReadonlyKeys<Todo1>>>,
Expect<Equal<'title' | 'description', GetReadonlyKeys<Todo2>>>,
]
interface Todo1 {
readonly title: string
description: string
completed: boolean
}
interface Todo2 {
readonly title: string
readonly description: string
completed?: boolean
}
- 首先可以确定的是返回类型是联合类型,类型值是泛型
T中被readonly修饰的索引键名 - 为了挑选出符合条件的键需要对泛型
T的每一项进行比较,这时候需要确定比较的方式,一个比较好的思路是利用Equal直接和符合条件的索引作比较,即Equal<{ [key in keyof T]: T[key] } , { readonly [Q]: T[Q] }> - 为了实现对泛型的每一项进行比较需要有两个前置工作 - 利用联合类型分发
key、通过Pick提取当前key的类型 - 利用联合类型分发
key要求联合类型key约束为T类型,即type GetReadonlyKeys<T, Key extends keyof T> Pick<T, K>会从类型T中选择出属性K,构造成一个新的类型,所以有Equal<Pick<T, K>, Readonly<Pick<T, K>>>- 结合上述分析得到
type GetReadonlyKeys<T, K extends keyof T> = Equal<Pick<T, K>, Readonly<Pick<T, K>>> extends true ? K : never
Tips:当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。