# 前置知识
今日 【easy - 7.readonly】、【middle - 3.omit】
在这之前需要掌握一点Ts基础知识,可以参考学习记录TypeScript学习记录-[数据类型]、TypeScript学习记录-[类和接口]、TypeScript学习记录-[枚举和泛型]、TypeScript学习记录-[类型别名]
# 二、题目分析
# 1. readonly
Readonly 会接收一个泛型参数,并返回一个完全一样的类型,只是所有属性都会被 readonly 所修饰
type MyReadonly<T> = any
/* _____________ 测试用例 _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<MyReadonly<Todo1>, Readonly<Todo1>>>,
]
interface Todo1 {
title: string
description: string
completed: boolean
meta: {
author: string
}
}
- 首先可以确定的是返回类型是
object
(索引类型index Type), 且其属性都会被readonly
,即type MyReadonly<T> = { readonly key:value }
,且包含的键值对个数 key
应循环取自泛型T
的索引,value
应循环取自泛型T
的索引的值T[Key]
,需使用keyof T
查询索引类型中所有的索引,结合运算符in
进行遍历,从而得到type MyReadonly<T> = { readonly [k in keyof T]: T[k] }
# 2.Omit
不使用 Omit 实现 TypeScript 的 Omit<T, K> 泛型
/* _____________ Your Code Here _____________ */
type MyOmit<T, K> = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<Expected1, MyOmit<Todo, 'description'>>>,
Expect<Equal<Expected2, MyOmit<Todo, 'description' | 'completed'>>>,
]
// @ts-expect-error
type error = MyOmit<Todo, 'description' | 'invalid'>
interface Todo {
title: string
description: string
completed: boolean
}
interface Expected1 {
title: string
completed: boolean
}
interface Expected2 {
title: string
}
- 首先可以确定的是返回类型是
object
(索引类型index Type),且其属性均属于泛型T
,从而有type MyOmit<T, K> = { [key in keyof T]: T[key] }
k
中包含了需要排除的索引,即key in keyof K
可以写作key in keyof Keys
, 从而有type MyOmit<T, key in keyof Keys> = { [key in keyof T]: T[key] }
,不过这样就产生了两个遍历联合类型的in
运算,形成了嵌套判断。- 这种情况下一般采用条件类型
extends
运算符进行判断,即k extends keyof T
、key extends k ? never : key
。其中第一个extends
结合keyof
使用可以约束K
的条件,即K
的联合项必须来自接口T
的属性否则Ts
就会报错,此时extends
通过推迟解析条件类型得到了一个联合类型;第二个extends
用作条件类型判断,逻辑是key
类型可被赋值于k
类型则被赋予never
(),否则赋予key
类型,从而排除掉泛型k
中的key
类型 - 结合上述分析,我们可以得到
type MyOmit<T, Keys extends keyof T> = { [key in keyof T as key extends Keys ? never : key]: T[key] }
,需要注意的是这里使用到了重映射运算符as
,可以理解为前述中两个遍历联合类型的in
运算中的嵌套链接。