TypeScript 类型挑战的集合
由于在学习源码的时候,有些typescript看不懂,所以通过练习来学习typescript
类型。以下是最近练习的记录!
官网
vscode插件:
前置知识
extends
学习自 blog.csdn.net/qq_34998786…
// 首先来看下extends 咋用
// 举个例子
type A1 = 'x' extends 'x' ? string : number; // string
type A2 = 'x' | 'y' extends 'x' ? string : number; // number
type P<T> = T extends 'x' ? string : number;
type A3 = P<'x' | 'y'> // string|number
type A4 = P<never> // never
//never 会比较特殊,则
type P1<T> = T extends 'x' ? string : never;
type A5 = P1<'x' | 'y'> // string
对于使用extends关键字的条件类型(即上面的三元表达式类型),如果extends前面的参数是一个泛型类型,当传入该参数的是联合类型,则使用分配律计算最终的结果。分配律是指,将联合类型的联合项拆成单项,分别代入条件类型,然后将每个单项代入得到的结果再联合起来,得到最终的判断结果。 never会比较特殊,never被认为是空的联合类型,也就是说,没有联合项的联合类型,所以还是满足上面的分配律,然而因为没有联合项可以分配,所以P的表达式其实根本就没有执行,所以A2的定义也就类似于永远没有返回的函数一样,是never类型的。
infer
用于获取类型
Easy
Pick
通过从中 T 选取属性 K 集来构造类型
type MyPick<T,K extends keyof T> = {
[P in K]: T[P]
}
Readonly
构造一个类型,并将T的所有属性设置为只读,这意味着构造类型的属性不能重新分配
type MyReadonly<T> ={
readonly [p in keyof T] = T[P]
}
TupleToObject
给定一个数组,将其转换为对象类型,并且键值在提供的数组中
type TupleToObject<T extends any[]> = {
[P in T[number]]:T[P]
}
First of Array
实现一个泛型,该泛型 First 采用 Array T 并返回其第一个元素的类型。
1.type First<T extends any[]> = T[number] extends never?never:T[0]
2.type First<T extends any[]> = T extends [] ? never : T[0]
3.type First<T extends any[]> = T extends [infer A, ...infer rest ]?A:never
Length of Tuple
对于给定的元组,您需要创建一个泛型 Length ,选择元组的长度
type Length<T> = T extends {length:infer R}?R:never
Exclude
从可 U 分配给的类型中 T 排除
type Exclude<T,U> = T extends U ? never : T
Awaited
如果我们有一个像 Promise 这样的包装类型。我们如何获得包装类型内部的类型?
type MyAwaited<T extends PromiseLike<any | PromiseLike<any>>>
=
T extends PromiseLike<infer U> ? U extends PromiseLike<any> ? MyAwaited<U> : U : never
If
实现接受条件 C 、真值和假值 T F 的 util 类型 If<C, T, F> 。 C 应为任一 true 类型 false T , F 可以是任何类型。
type If<C extends boolean, T, F> = C extends true?T:F
Concat
在类型系统中实现 typescript Array.concat 函数。类型采用两个参数。输出应该是一个新的数组,其中包含按 ltr 顺序的输入
type Concat<T extends Tuple, U extends Tuple> = [...T,...U]
Includes
在类型系统中实现 typescript Array.includes 函数。类型采用两个参数。输出应为布尔值 true 或 false .
type IsEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends (<G>() => G extends U ? 1 : 2) ? true : false
type Includes<T extends readonly any[], U> = IsEqual<{
[P in keyof T as T[P] extends U ? 0 : never]: T[P]
}, { 0: U }>
Push
实现 的 Array.push 通用版本
type Push<T extends unknown[], U> = [...T,U]
Unshift
实现的类型 Array.unshift 版本
type Unshift<T extends unknown[], U> = [U,...T]
Parameters
实现内置参数泛型而不使用它
type MyParameters<T extends (...args:any[])=>any> = T extends (...any:infer U)=>any?U:any
Medium
Get Return Type
在不使用它的情况下实现内置 ReturnType 泛型。
type MyReturnType<T extends (...args:any[])=>unknown> = T extends (...args:any)=>infer U?U:never
Omit
通过从中 T 选取所有属性然后删除 K 来构造类型,看的solution:用as非常棒
type MyOmit<T, K extends keyof T> ={
[P in keyof T as P extends K ? never: P ] : T[P]
}
Readonly 2
K 指定应 T 设置为“只读”的属性集。如果未提供,它 K 应使所有属性只读,就像普通 Readonly 属性一样。
type Readonly2<T,K>={
[P in keyof T as P extends K ? never:P]:K[P]
}&{readonly [P in K ]:T[P}
TupleToUnion
实现一个泛型,该泛型 TupleToUnion 涵盖元组的值到其值联合。
type TupleToUnion<T extends any[]> =T[number]
Chainable Options
在这个挑战中,你需要键入一个对象或一个类 - 无论你喜欢什么 - 提供两个函数 option(key, value) 和 get() .在 中 option ,可以通过给定的键和值扩展当前配置类型。我们应该通过 访问 get 最终结果。 下面是找到的最好的答案及解释:
- 可以使用 T = {} 来作为默认值,甚至默认参数与默认返回值,再通过递归传递 T 即可实现递归全局记录
- option 是一个函数接收两个值:K 和 V,为了约束 key 不可重复必须范型传入,value 是任意类型范型不做约束直接透传
- 先验证重复 key,实现传入相同 key 报错
- 然后发现案例3无法通过,案例3是传入了相同的 key 但类型不同,因此在 KextendskeyofT 后面增加验证只有类型相同才返回 never
- 最后直接 & 联合并不能将相同 key 的类型覆盖,因此用 Omit 去掉前一个类型中相同的 key
type Chainable<T = {}> = {
option:<K extends T,V>(key:K extends keyof T ? never:K,value:V)=>Chainable<Omit<T,K>&Record<K,V>>
get:()=>T
}
Last of Array
Implement a generic Last that takes an Array T and returns its last element. 实现一个泛型,该泛型 Last 采用 Array T 并返回其最后一个元素。
type Last<T extends any[]> =T extends [...any,infer U] ? U:never
Pop
Implement a generic Pop that takes an Array T and returns an Array without it's last element. 实现一个泛型,该泛型 Pop 采用数组 T 并返回一个没有最后一个元素的数组。
type Pop<T extends any[]> =T extends [...infer U,any]?U:[]
Promise.all
Type the function PromiseAll that accepts an array of PromiseLike objects, the returning value should be Promise where T is the resolved result array. 键入接受 PromiseLike 对象数组的函数 PromiseAll ,返回值应为 Promise where T 是解析的结果数组。
declare function PromiseAll<T extends any[]>(values: readonly [...T]): Promise<{ [K in keyof T]: T[K] extends Promise<infer U> | infer U ? U : T[K] }>
Type Lookup
Sometimes, you may want to look up a type in a union by its attributes. 有时,您可能希望按属性在联合中查找类型。 In this challenge, we would like to get the corresponding type by searching for the common type field in the union Cat | Dog. In other words, we will expect to get Dog for LookUp<Dog | Cat, 'dog'> and Cat for LookUp<Dog | Cat, 'cat'> in the following example. 在这个挑战中,我们希望通过搜索并集中 Cat | Dog 的公共 type 字段来获得相应的类型。换句话说,我们希望在以下示例中得到 Dog for 和 Cat for LookUp<Dog | Cat, 'dog'> LookUp<Dog | Cat, 'cat'> 。
type Lookup<U extends {type:string},T extends string> = U extends {type:T} ? U:never
TrimLeft
Implement TrimLeft which takes an exact string type and returns a new string with the whitespace beginning removed. 实现 TrimLeft ,它采用精确的字符串类型并返回一个删除空格开头的新字符串。
type Whitespace = " " | "\n" | "\t"
type TrimLeft<S extends string> = S extends `${Whitespace}${infer U}`? TrimLeft<U> : S
Trim
Implement Trim which takes an exact string type and returns a new string with the whitespace from both ends removed. 实现 Trim ,它采用精确的字符串类型并返回一个新字符串,其中两端的空格都被删除了。
type WhiteList = ' ' | "\n" | "\t"
type Trim<S extends string> = S extends `${WhiteList}${infer U}`|`${infer U}${WhiteList}`?Trim<U>:S
Capitalize
Implement Capitalize which converts the first letter of a string to uppercase and leave the rest as-is. 实现 Capitalize 将字符串的第一个字母转换为大写,其余字母保持原样。
type MyCapitalize<S extends string> = S extends `${infer U}${infer I}`? `${Uppercase<U>}${I}`:S
Replace
Implement Replace<S, From, To> which replace the string From with To once in the given string S
实现 Replace<S, From, To>
将字符串替换为 To 给定字符串 From S 中的一次
type Replace<S extends string, From extends string, To extends string> = From extends ""?S:S extends `${infer U}${From}${infer V}`?`${U}${To}${V}`:S
ReplaceAll
Implement ReplaceAll<S, From, To> which replace the all the substring From with To in the given string S 实现 ReplaceAll<S, From, To> ,将给定字符串 S 中的所有子字符串 From 替换为To
type ReplaceAll<S extends string, From extends string, To extends string>= From extends ""?S:S extends `${infer U}${From}${infer V}`?`${U}${To}${ReplaceAll<`${V}`,From,To>}`:S
Append Argument
For given function type Fn, and any type A (any in this context means we don't restrict the type, and I don't have in mind any type 😉) create a generic type which will take Fn as the first argument, A as the second, and will produce function type G which will be the same as Fn but with appended argument A as a last one. 对于给定的函数类型,和任何类型(在这种情况下,任何类型意味着我们不限制类型,而且我不考虑任何类型)创建一个泛型类型,该泛型类型将作为第一个参数,作为第二个参数,并将生成函数类型,该函数类型 Fn A 😉 G 将与最后一个相同 Fn , A 但附加参数 A 作为最后一个。 Fn
type AppendArgument<Fn extends (...args:any[])=>any, A> = Fn extends (...args:infer V)=>infer U?( ...args:[...V,A])=>U:never
Permutation
Implement permutation type that transforms union types into the array that includes permutations of unions.
实现将联合类型转换为包含联合排列的数组的排列类型。
下方是找到的最佳答案:
这里利用了extends 假如extends前面是泛型 则当传入该参数的是联合类型,则使用分配律计算最终的结果
type Permutation<T,K=T> = [T] extends [never]?[]:K extends K?[K,...Permutation<Exclude<T,K>>]:never
Length of String
Compute the length of a string literal, which behaves like String#length. 计算字符串文本的长度,其行为类似于 String#length 。
type LengthOfString<T extends String,K extends any[]=[]>=T extends `${infer U}${infer V}`?LengthOfString<V,[...K,U]>:K["length"]
Flatten
In this challenge, you would need to write a type that takes an array and emitted the flatten array type. 在此挑战中,您需要编写一个接受数组并发出平展数组类型的类型。
type Flatten<T extends any[],K extends any[]=[]> =T extends [infer U,...infer V]?U extends [...infer A]?Flatten<[...A,...V],K>:Flatten<[...V],[...K,U]> :K
Append to Object Implement a type that adds a new field to the interface. The type takes the three arguments. The output should be an object with the new field. 实现向接口添加新字段的类型。该类型采用三个参数。输出应该是具有新字段的对象。
type AppendToObject<T, U extends string, V> = {
[P in keyof T|U]:P extends U?V:P extends keyof T?T[P]:never
}