type-challenges项目的一些练习记录 当做字典来用
MyPick
type MyPick<T, K extends keyof T> = {
[P in K]: T[P]
}
注释
这个类型别名 MyPick 的作用是从类型 T 中挑选出某些属性,并构造一个新的类型。它类似于 TypeScript 内置的 Pick 类型。
类型参数
T: 一个对象类型,你可以从中挑选属性。K extends keyof T: 一个联合类型,表示T类型中的一组键(即属性名)。
关键点
K extends keyof T限制了K必须是T的键之一。这确保了你只能挑选存在于T中的属性。
映射类型
映射类型是 TypeScript 中的一种高级类型,它允许你创建基于另一个类型的新类型。我们这里就是在使用映射类型。
分解映射类型 { [P in K]: T[P] }
[P in K]: - 这是一个索引签名,它表示对于联合类型K中的每一个属性P,我们都将其包含在新类型中。 - 具体来说,P将遍历K中的所有属性。T[P]: - 我们通过T[P]获取T类型中属性P的类型。 - 这意味着新类型中的属性P将拥有与T中相同的类型。
MyReadonly
type MyReadonly<T> = {
readonly [K in keyof T]: T[K]
}
注释
这个类型别名 MyReadonly 的作用是将对象类型 T 中的所有属性设置为只读(readonly)。它类似于 TypeScript 内置的 Readonly 类型。
类型参数
T: 一个对象类型,你希望将其属性设置为只读。
映射类型与关键字
这个类型别名利用了 TypeScript 的映射类型和 readonly 修饰符来实现目标。
分解映射类型 { readonly [K in keyof T]: T[K] }
readonly: -readonly关键字用于将属性设置为只读。只读属性在初始化之后不能再被修改。[K in keyof T]: - 这是一个索引签名,用于遍历T类型的键(即属性名)。 -keyof T生成一个联合类型,包含T类型的所有键。 -K in keyof T意味着对于T中的每一个键K,我们都将其包含在新类型中。T[K]: - 我们通过T[K]获取T类型中属性K的类型。 - 这意味着新类型中的属性K将拥有与T中相同的类型,但是现在它们是只读的。
TupleToObject
type TupleToObject<T extends readonly (string | number | symbol)[]> = {
[P in T[number]]: P
}
注释
这个类型别名 TupleToObject 用于将一个包含字符串、数字或符号的元组转换成对象类型,元组中的每个元素将成为对象中的键和值。
类型参数
T extends readonly (string | number | symbol)[]:- 这是一个泛型参数
T,表示一个只读数组(元组),其中的元素类型可以是字符串、数字或符号。这确保了T中的元素可以有效地用作对象的键。
映射类型与索引类型
这个类型别名利用了 TypeScript 的映射类型和索引类型来实现目标。
关键点
[P in T[number]]: -T[number]是 TypeScript 中的一种语法,用于获取元组T中所有元素的联合类型。- 举例来说,如果
T是['a', 'b', 'c'],那么T[number]就是'a' | 'b' | 'c'。 -[P in T[number]]是一个遍历联合类型的映射类型。对于T中的每一个元素P,我们都将其作为对象的键。
- 举例来说,如果
{ [P in T[number]]: P }: - 对象的键和值都为P,即元组中的每一个元素既是新对象中的键,也是该键对应的值。
First
// answer1
type First<T extends any[]> = T extends [] ? never : T[0]
// answer2
// type First<T extends any[]> = T['length'] extends 0 ? never : T[0]
// answer3
// type First<T extends any[]> = T extends [infer A, ...infer rest] ? A : never
注释-answer1
类型参数
T extends any[]:- 这是一个泛型参数
T,它必须是一个数组类型。数组中的元素可以是任何类型(即any[])。
条件类型
TypeScript 中的条件类型类似于 JavaScript 中的三元表达式 condition ? trueExpression : falseExpression,它在类型层次上进行条件判断和选择。
分解条件类型
T extends []: - 这里的extends用于检查类型兼容性。 -T extends []用于判断T是否为一个空数组类型,即没有任何元素的数组。? never: - 如果T确实是一个空数组类型,那么返回never类型。 -never类型表示的是那些永不存在的值。在这里,它被用来表示空数组没有第一个元素。: T[0]: - 如果T不是一个空数组类型,则返回T[0],即数组T的第一个元素的类型。
Length
type Length<T extends readonly any[]> = T['length']
注释
类型参数
T extends readonly any[]:- 这是一个泛型参数
T,表示它必须是一个只读数组类型。数组中的元素可以是任何类型(即any[])。
数组长度属性
在 TypeScript 中,数组类型有一个预定义的属性 length,它代表数组的长度。我们可以通过类型系统访问这个属性来获取数组的长度类型。
分解类型
T['length']: - 这是在类型级别上访问数组T的length属性。 - 对于任意数组类型T,T['length']的值是一个数字字面量类型,表示该数组的长度。
MyExclude
type MyExclude<T, U> = T extends U ? never : T
注释
类型参数
T: 待处理的类型,可以是任何类型的联合类型。U: 要从T中排除的类型,也可以是任何类型的联合类型。
条件类型
TypeScript 中的条件类型类似于 JavaScript 中的三元表达式 condition ? trueExpression : falseExpression,它在类型层次上进行条件判断和选择。
分解条件类型
T extends U: - 这里的extends用于检查类型兼容性。 -T extends U判断T是否可以赋值给U,即T是否是U的子类型。如果T是U的子类型(或T中的某些子类型是U),则条件为真。? never: - 如果T中的某个成员可以赋值给U,那么在这个条件类型中,该成员将被排除掉,即返回never类型。 -never类型表示的是那些永不存在的值。在这里,它被用来表示应该从结果中排除这些成员。: T: - 如果T中的某个成员不能赋值给U,则保留该成员并返回它的类型。
MyAwaited
type MyAwaited<T extends PromiseLike<any>> = T extends PromiseLike<infer U>
? U extends PromiseLike<any>
? MyAwaited<U>
: U
: never
注释
类型参数
T extends PromiseLike<any>: 该类型参数T必须是一个类 Promise 类型的对象,即T必须实现then方法(例如Promise或自定义的 Promise-like 对象)。
条件类型和推断
TypeScript 中的条件类型允许在类型系统中进行条件判断和选择,而推断(infer)则用于从复杂类型中提取某部分类型。
分解条件类型和推断
T extends PromiseLike<infer U>: - 首先检查T是否是一个类 Promise 类型。如果是,则将PromiseLike的解析类型赋值给类型变量U。 -infer U是用来提取PromiseLike的泛型参数的。这允许我们获取到Promise或类Promise对象内部所包装的类型。U extends PromiseLike<any>: - 如果U本身也是一个类 Promise 类型,那么继续递归地解析它。 - 使用MyAwaited<U>来继续展开此类 Promise 的内部值,直到达到最里面的非 Promise 值为止。: U: - 如果U不是类 Promise 类型,那么就返回U。: never: - 如果T不是类 Promise 类型,返回never。这意味着传入的T必须是类 Promise 类型,否则类型不合法。
If
type If<C, T, F> = C extends true ? T : F
注释
类型参数
C: 条件类型,用于判断是否为true。T: 如果C为true时返回的类型。F: 如果C为false时返回的类型 。
条件类型
TypeScript 中的条件类型类似于 JavaScript 中的三元表达式 condition ? trueExpression : falseExpression,它在类型层次上进行条件判断和选择。
分解条件类型
C extends true: -extends用于检查类型兼容性。在这里,它用于检查C是否可以赋值给true。 - 也就是说,判断C是否为true,如果是,那么条件就为真。? T: - 如果C为true,那么返回类型T。: F: - 如果C为false,那么返回类型F。
Concat
type Concat<T extends readonly any[], U extends readonly any[]> = [...T, ...U]
注释
类型参数
T extends readonly any[]:- 这是泛型参数
T,必须是一个只读数组类型。readonly表示该数组不可变。 - 数组中的元素可以是任何类型(即
any[])。 U extends readonly any[]:- 这是泛型参数
U,也必须是一个只读数组类型,同样地,元素可以是任何类型。
展开运算符
TypeScript 中的展开运算符(spread operator)... 可以用于在类型系统中将元组或数组类型展开为单个元素。通过使用展开运算符,我们能够将两个数组类型合并为一个新的数组类型。
Includes
type IsEqual<T, U> =
(<G>() => G extends T ? 1 : 2) extends
(<G>() => G extends U ? 1 : 2)
? true
: false
type Includes<Value extends readonly any[], Item> =
Value extends [infer First, ...infer Rest]
? IsEqual<First, Item> extends true
? true
: Includes<Rest, Item>
: false
注释-IsEqual
工作原理
IsEqual 类型别名用于判断两个类型 T 和 U 是否相等。它通过创建匿名函数类型并利用条件类型来实现这一点。
<G>() => G extends T ? 1 : 2: - 这是一个泛型箭头函数,它接受一个泛型参数G。 - 如果G能够赋值给类型T,则返回类型1,否则返回类型2。<G>() => G extends U ? 1 : 2: - 这是另一个泛型箭头函数,工作原理同上,但这里是检查G是否能够赋值给U。- 比较两个函数类型:
-
(<G>() => G extends T ? 1 : 2) extends (<G>() => G extends U ? 1 : 2): - 如果这两个函数类型能够互相赋值,则说明T和U是相等的,返回true。 - 否则返回false。
注释-Includes
工作原理
Includes 类型别名用于检查数组类型 Value 中是否包含某个类型 Item。它使用递归泛型和类型推断来实现这一点。
Value extends [infer First, ...infer Rest]: - 这里使用了类型推断(infer)来将数组Value分解为首元素First和剩余元素Rest。 - 如果Value能被分解,则进入三元操作符,否则返回false。IsEqual<First, Item> extends true- 使用前面定义的IsEqual类型来比较First和Item。 - 如果First和Item相等,则返回true。Includes<Rest, Item>: - 如果First和Item不相等,则递归地检查剩余的元素Rest。
Push
type Push<T extends readonly any[], U> = [...T, U]
注释
类型参数
T extends readonly any[]:- 这是泛型参数
T,必须是一个只读数组类型。readonly表示该数组不可变。 - 数组中的元素可以是任何类型(即
any[])。 U:- 这是要添加到数组
T末尾的元素,它的类型没有限制,可以是任何类型。
展开运算符(Spread Operator)
TypeScript 中的展开运算符 ... 可以用于在类型系统中将元组或数组类型展开为单个元素。通过使用展开运算符,我们能够将数组类型 T 的所有元素与新元素 U 合并到一个新的数组类型中。
Unshift
type Unshift<T extends readonly any[], U> = [U, ...T]
注释
类型参数
T extends readonly any[]:- 这是泛型参数
T,必须是一个只读数组类型。readonly表示该数组不可变。 - 数组中的元素可以是任何类型(即
any[])。 U:- 这是要添加到数组
T开头的元素,它的类型没有限制,可以是任何类型。
展开运算符(Spread Operator)
TypeScript 中的展开运算符 ... 可以用于在类型系统中将元组或数组类型展开为单个元素。通过使用展开运算符,我们能够将新元素 U 与数组类型 T 的所有元素合并到一个新的数组类型中,以保证 U 出现在数组的开头。
MyParameters
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never
注释
类型参数
T extends (...args: any[]) => any:- 这是泛型参数
T,必须是一个函数类型。 (...args: any[]) => any表示该类型必须是一个接受任意数量和类型参数并返回任意类型值的函数。
条件类型和类型推断
TypeScript 中的条件类型类似于 JavaScript 中的三元表达式 condition ? trueExpression : falseExpression。在这里,我们结合使用条件类型和类型推断来提取函数的参数类型。
分解条件类型
T extends (...args: infer P) => any: - 条件类型用于检查T是否符合提供的模式。 -(...args: infer P)使用infer关键字来推断函数参数列表的类型,并将其赋值给类型变量P。 - 如果T符合这个模式,那么P将包含T的参数列表类型。? P : never: - 如果条件为真(即T符合函数类型并成功推断出参数类型),则返回被推断的参数类型P。 - 否则返回never,表示T不是一个有效的函数类型。