持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情
1. 引言
前面14个章节咱们大致介绍了一些TypeScript常用的类型与一些操作语法,接下来我们会开展类型体操测试,这是由一个开源项目
https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md 提供的TypeScript 类型体操姿势合集题型,目的是为了让大家更好的了解TS的类型系统,编写自己的类型工具,或者单纯的享受挑战的乐趣!
接下来我们就由简单入深,开始一步步闯关学习
2. 题型
- 实现 TS 内置的
Pick<T, K>,但不可以使用它。从类型T中选择出属性K,构造成一个新的类型
interface Todo {
title: string
description: string
completed: boolean
}
type MyPik<T,K extends keyof T> = {
[P in K]: T[P]
}
- 不要使用内置的Readonly,自己实现一个。该 Readonly 会接收一个 泛型参数,并返回一个完全一样的类型,只是所有属性都会被 readonly 所修饰。
type MyReadonly<T> = {
readonly [P in keyof T] = T[P]
}
interface Todo1 {
title: string
description: string
completed: boolean
meta: {
author: string
}
}
type Demo = MyReadonly<Todo1>
let a:Demo = {
title: '张三',
description: '描述',
completed: true,
meta: {
author: 'guozi'
}
}
a.title = '李四' // error: Cannot assign to 'title' because it is a read-only property.
a.description = '李四' // error: Cannot assign to 'description' because it is a read-only property.
a.completed = false // error: Cannot assign to 'completed' because it is a read-only property.
a.meta = {
author: 'guozizzz'
} // error: Cannot assign to 'meta' because it is a read-only property.
a.meta.author = 'guozizzzwwwww' // ok
- 传入一个元组类型,将这个元组类型转换为对象类型,这个对象类型的键/值都是从元组中遍历出来。
// 提纲补充:
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
type result = TupleToObject<typeof tuple> // expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
结题思路: 第一步:Ts中对象的键值遍历是通过keyof操作符
type User = {
name: string
age: number
}
type Keyuser = keyof User // 'name' | 'age'
第二步:元组或数组中的遍历是通过 元祖对象[number]
type Arr = [1,2,3,5]
type KeyArr = Arr[number] // 1 | 2 | 3 | 5
第三步:例子中as const断言后的类型为不可写的数组类型,所以要约束传入的参数即使用extends构造一个不可写的数组类型
extends readonly 元祖
结论:
type TupleToObject<T extends readonly any[]> = {
[P in T[number]]: P
}
- 实现一个通用
First<T>,它接受一个数组T并返回它的第一个元素的类型。
// 提纲补充:
type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]
type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3
解答:
type First<T extends any[]> = T extends [] ? never : T[0]
type Demo = First<[3, 2, 1]> // type Demo = 3
type Demo2 = First<[() => 123, { a: string }]> // type Demo2 = () => 123
type Demo3 = First<[]> // type Demo3 = never
type Demo4 = First<[undefined]> // type Demo4 = undefined