Type Challenges -- TS 练习题之 Medium 篇答案 (持续更新)
感谢 type-challenges 提供的题目
前言
建议 fork 原仓库地址在本地进行答题
原仓库地址:type-challenges
答案仓库地址: github.com/fortress-fi…
相关文章
Type Challenges -- TS 练习题之 Easy 篇答案
Type Challenges -- TS 练习题之 Medium 篇答案 (持续更新)
Type Challenges -- TS 练习题之 Hard 篇答案 (持续更新)
medium
00002-medium-return-type
type MyReturnType<T> = T extends (...args: any[]) => infer P ? P : never
00003-medium-omit
type MyOmit<T, K extends keyof T> = {
[P in MyExclude<keyof T, K>]: T[P]
}
00008-medium-readonly-2
type MyReadonly2<T, K extends keyof T = keyof T> = {
readonly [P in K]: T[P]
} & {
[P in MyExclude<keyof T, K>]: T[P]
}
00009-medium-deep-readonly
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends Record<string, unknown>
? T[P]
: DeepReadonly<T[P]>
}
00010-medium-tuple-to-union
type TupleToUnion<T extends any[]> = T[number]
00012-medium-chainable-options [使用可串联(Chainable/Pipeline)的函数构造一个对象]
type Chainable<T extends Object = {}> = {
option<K extends string, V>(
key: K extends keyof T ? never : K,
value: V,
): Chainable<T & { [P in K]: V }>
get(): { [P in keyof T]: T[P] }
}
00459-medium-flatten [
00015-medium-last [实现一个通用Last<T>,它接受一个数组T并返回其最后一个元素的类型]
type Last<T extends any[]> = T extends [...any[], infer K] ? K : never
00016-medium-pop [实现一个通用Pop<T>,它接受一个数组T并返回一个没有最后一个元素的数组]
type Pop<T extends any[]> = T extends [...infer K, any] ? K : never
00020-medium-promise-all
declare function PromiseAll<T extends unknown[]>(
values: readonly [...T],
): Promise<{ [P in keyof T]: T[P] extends Promise<infer K> ? K : T[P] }>
00062-medium-type-lookup [使用指定属性作为条件,筛选出联合属性中符合要求的那个]
type LookUp<U extends { type: string }, T> = U extends { type: T } ? U : never
00106-medium-trimleft [trimleft 方法的类型定义]
type TrimCharacter = ' ' | '\n' | '\t'
type TrimLeft<S extends string> = S extends `${TrimCharacter}${infer T}`
? TrimLeft<T>
: S
00108-medium-trim [trim 方法的类型定义]
type TrimCharacter2 = ' ' | '\n' | '\t'
type Trim<S extends string> = S extends `${TrimCharacter2}${infer T}`
? Trim<T>
: S extends `${infer T}${TrimCharacter2}`
? Trim<T>
: S
00110-medium-capitalize [首字母大写]
type MyCapitalize<S extends string> = S extends `${infer T}${infer K}`
? `${Uppercase<T>}${K}`
: ''
00116-medium-replace [replace 类型定义]
type Replace<
S extends string,
From extends string,
To extends string,
> = S extends `${infer T}${From}${infer E}`
? `${T}${From extends '' ? '' : To}${E}`
: S
00119-medium-replaceall [replaceAll 类型定义]
type ReplaceAll<
S extends string,
From extends string,
To extends string,
> = S extends `${infer F}${From}${infer E}`
? From extends ''
? S
: `${ReplaceAll<F, From, To>}${To}${ReplaceAll<E, From, To>}`
: S
00191-medium-append-argument [追加参数类型]
type AppendArgument<Fn extends (...param: any[]) => any, A> = Fn extends (
...param: infer T
) => infer R
? (...param: [...T, A]) => R
: never
00296-medium-permutation [实现联合类型的全排列,将联合类型转换成所有可能的全排列数组的联合类型]
// NOTE: 错题本
type Permutation<T, U = T> = [T] extends [never]
? []
: T extends U
? [T, ...Permutation<Exclude<U, T>>]
: []
此处可以开出 extends 在执行的过程中,对联合类型拆解后进行循环执行,并将循环后的结果组成了新的联合类型,示例:
type Test<T> = T extends T ? [T] : []
type result = Test<'a' | 'b'>
// type result = ["a"] | ["b"]
00298-medium-length-of-string [计算字符串的长度,类似于 String#length ]
type LengthOfString<
S extends string,
U extends any[] = [],
> = S extends `${infer F}${infer O}`
? LengthOfString<O, [...U, F]>
: U['length']
00459-medium-flatten [数组 flatten 方法类型定义]
type Flatten<T extends any[], N extends any[] = []> = T extends [
infer F,
...infer O,
]
? F extends any[]
? Flatten<O, [...N, ...Flatten<F>]>
: Flatten<O, [...N, F]>
: N
00527-medium-append-to-object
type AppendToObject<T, U extends string, V> = {
[P in keyof T | U]: P extends keyof T ? T[P] : V
}
00529-medium-absolute [取绝对值]
type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer U}`
? U
: `${T}`
00531-medium-string-to-union [split string]
type StringToUnion<T extends string> = T extends `${infer S}${infer O}`
? S | StringToUnion<O>
: never
00599-medium-merge [合并两个 Object 类型]
type Merge<F, S> = {
[P in keyof F | keyof S]: P extends keyof S
? S[P]
: P extends keyof F
? F[P]
: never
}
00612-medium-kebabcase [kebabcase 格式转换]
type KebabCase<
S extends string,
B extends string = '',
> = S extends `${infer F}${infer O}`
? F extends Uppercase<F>
? F extends Lowercase<F>
? KebabCase<O, `${B}${F}`>
: KebabCase<O, `${B}${B extends '' ? '' : '-'}${Lowercase<F>}`>
: KebabCase<O, `${B}${F}`>
: B
00645-medium-diff [获取两个接口类型中的差值属性]
type DiffKey<C, C1> = C extends C1 ? never : C
type Diff<O, O1> = {
[P in DiffKey<keyof (O & O1), keyof (O | O1)>]: P extends keyof O
? O[P]
: P extends keyof O1
? O1[P]
: never
}
00949-medium-anyof [类型接收一个数组,如果数组中任一个元素为真,则返回 true,否则返回 fasle。如果数组为空,返回 false]
type AnyOf<T extends readonly any[]> = T extends [infer F, ...infer O]
? F extends 0 | '' | false | [] | Record<string, never>
? AnyOf<O>
: true
: false
表示一个空对象的方法:Record<string, never>
01042-medium-isnever [never 判断]
type IsNever<T> = [T] extends [never] ? true : false
如果直接使用 T 做判断,当 T 为 never 的时候,将始终返回 never
01097-medium-isunion [联合类型判断]
type IsUnion<T, N = T> = T extends T ? ([N] extends [T] ? false : true) : never
01130-medium-replacekeys [替换值类型]
type ReplaceKeys<U, T, Y> = {
[P in keyof U]: P extends T ? (P extends keyof Y ? Y[P] : never) : U[P]
}
01367-medium-remove-index-signature [移除索引]
type RemoveIndexSignature<T> = {
[P in keyof T as P extends `${infer K}` ? K : never]: T[P]
}
这里的 as 作为对 P 的进一步定义使用
01978-medium-percentage-parser [分离正负,数字,单位]
type PercentageParser<
A extends string,
S extends string = '',
N extends string = '',
U extends string = '',
> = A extends `${infer F}${infer O}`
? F extends '+' | '-'
? PercentageParser<O, F, '', ''>
: F extends '%'
? PercentageParser<O, S, N, F>
: PercentageParser<O, S, `${N}${F}`, U>
: [S, N, U]
02070-medium-drop-char [移除指定字符]
type DropChar<S, C, R extends string = ''> = S extends `${infer F}${infer O}`
? F extends C
? DropChar<O, C, `${R}`>
: DropChar<O, C, `${R}${F}`>
: R
02257-medium-minusone (未处理)
02595-medium-pickbytype [筛选对象中,值符合要求类型的键]
type PickByTypeFilter<
T extends Record<string, any>,
P extends keyof T,
U,
> = T[P] extends U ? P : never
type PickByType<T, U> = {
[P in keyof T as PickByTypeFilter<T, P, U>]: T[P]
}
02688-medium-startswith [接收两个string类型参数,然后判断T是否以U开头,根据结果返回true或false]
type StartsWith<
T extends string,
U extends string,
S extends string = '',
> = T extends `${infer F}${infer O}`
? U extends S
? true
: StartsWith<O, U, `${S}${F}`>
: false
02693-medium-endswith [接收两个string类型参数,然后判断T是否以U结尾,根据结果返回true或false]
type EndsWith<
T extends string,
U extends string,
> = T extends `${infer _F}${infer O}`
? U extends T
? true
: EndsWith<O, U>
: false
02757-medium-partialbykeys [它接收两个类型参数T和K。K指定应设置为可选的T的属性集。当没有提供K时,它就和普通的 Partial<T> 一样使所有属性都是可选的]
type PartialByKeysMerge<T> = {
[P in keyof T]: T[P]
}
type PartialByKeys<T, K = keyof T> = PartialByKeysMerge<
{
[P in keyof T & K]?: T[P]
} & {
[P in Exclude<keyof T, K>]: T[P]
}
>
02759-medium-requiredbykeys [实现一个通用的 RequiredByKeys<T, K>,它接收两个类型参数T和K。K指定应设为必选的T的属性集。当没有提供K时,它就和普通的 Required<T> 一样使所有的属性成为必选的]
type PartialByKeysMerge<T> = {
[P in keyof T]: T[P]
}
type PartialByKeys<T, K = keyof T> = PartialByKeysMerge<
{
[P in keyof T & K]?: T[P]
} & {
[P in Exclude<keyof T, K>]: T[P]
}
>
02793-medium-mutable [取出 readonly 修饰词]
type Mutable<T extends object> = {
-readonly [P in keyof T]: T[P]
}
02852-medium-omitbytype [移除对象中值符合要求类型的键 ]
type OmitByType<T, U> = {
[P in keyof T as T[P] extends U ? never : P]: T[P]
}
02946-medium-objectentries [Object.entries 的类型定义]
type ObjectEntries<T, K = keyof T, O = Required<T>> = K extends keyof O
? [K, O[K] extends [never] ? undefined : O[K]]
: undefined
03062-medium-shift [Array.shift 的类型定义]
type Shift<T> = T extends [infer _F, ...infer O] ? O : never
03188-medium-tuple-to-nested-object [Given a tuple type T that only contains string type, and a type U, build an object recursively.]
type TupleToNestedObject<T, U> = T extends [infer F, ...infer O]
? {
[P in F & string]: TupleToNestedObject<O, U>
}
: U
F & string 对 F 类型的进一步限定还是很常用的
03192-medium-reverse [Array.reverse 类型定义]
type Reverse<T, R extends unknown[] = []> = T extends [infer F, ...infer O]
? Reverse<O, [F, ...R]>
: R
03196-medium-flip-arguments [翻转函数参数]
type FlipArguments<T> = T extends (...args: infer A) => infer R
? (...args: Reverse<A>) => R
: never
03243-medium-flattendepth [数组扁平化(可以指定深度)]
type FlattenDepth<
T,
N extends number = 1,
U extends any[] = [],
C extends any[] = [],
> = T extends [infer F, ...infer O]
? F extends any[]
? N extends C['length']
? FlattenDepth<O, N, [...U, F], C>
: FlattenDepth<O, N, [...U, ...FlattenDepth<F, N, [], [...C, 1]>], C>
: FlattenDepth<O, N, [...U, F], C>
: U
03326-medium-bem-style-string [BEM 类型定义]
/**
* 如果是 "" 将会使用 D 进行替换
*/
type BEM_REPLACE_EMPTY<S extends string, D = never> = S extends '' ? D : S
type BEM_FLAT_M<
BE extends string,
M extends any[],
R extends string = '',
> = M extends [infer F, ...infer O]
? BEM_FLAT_M<BE, O, BEM_REPLACE_EMPTY<`${BE}--${F & string}` | R>>
: BEM_REPLACE_EMPTY<R, BE>
type BEM_FLAT_E<
B extends string,
E extends any[],
R extends string = '',
> = E extends [infer F, ...infer O]
? BEM_FLAT_E<B, O, BEM_REPLACE_EMPTY<`${B}__${F & string}` | R>>
: BEM_REPLACE_EMPTY<R, B>
type BEM<B extends string, E extends string[], M extends string[]> = BEM_FLAT_M<
BEM_FLAT_E<B, E>,
M
>
建议修改一下测试文件
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<BEM<'btn', ['price'], []>, 'btn__price'>>,
Expect<Equal<BEM<'btn', ['price'], ['warning', 'success']>, 'btn__price--warning' | 'btn__price--success' >>,
Expect<Equal<BEM<'btn', [], ['small', 'medium', 'large']>, 'btn--small' | 'btn--medium' | 'btn--large' >>,
Expect<Equal<BEM<'btn', [], []>, 'btn'>>,
Expect<Equal<BEM<'btn', ['price', 'size'], ['small', 'medium', 'large']>, 'btn__price--small' | 'btn__size--small' | 'btn__price--medium' | 'btn__size--medium' | 'btn__price--large' | 'btn__size--large'>>,
]
03376-medium-inordertraversal [Implement the type version of binary tree inorder traversal]
interface TreeNode {
val: number
left: TreeNode | null
right: TreeNode | null
}
type InorderTraversal<
T extends TreeNode | null,
TL = T extends TreeNode ? T['left'] : null,
TR = T extends TreeNode ? T['right'] : null,
R extends number[] = [],
> = T extends TreeNode
? [
...(TL extends TreeNode ? InorderTraversal<TL> : []),
T['val'],
...(TR extends TreeNode ? InorderTraversal<TR> : []),
]
: R
*04179-medium-flip [交换对象的 key 和 value]
type Flip<T> = {
[P in keyof T as `${T[P] & (string | number | bigint | boolean | null | undefined)}`]: P
}
此处可以关注一些 as 的使用方式
04182-medium-fibonacci-sequence [未处理]
04260-medium-nomiwase [列出字符串的所有排列组合]
type Combinations<T extends string, Y extends string> =
| T
| Y
| `${T}${Y}`
| `${Y}${T}`
type CombinationUnion<S extends string, Y extends string = S> = S extends Y
? Combinations<S, CombinationUnion<Exclude<Y, S>>>
: never
type AllCombinationsStringToUnion<
S,
R extends string = '',
> = S extends `${infer F}${infer O}`
? AllCombinationsStringToUnion<O, R | F>
: R
type AllCombinations<S extends string> =
| ''
| CombinationUnion<AllCombinationsStringToUnion<S>>
04425-medium-greater-than [比较数字大小]
type GreaterThan<
T extends number,
U extends number,
C extends any[] = [],
> = T extends U
? false
: T extends C['length']
? false
: U extends C['length']
? true
: GreaterThan<T, U, [...C, 1]>
04471-medium-zip [type exp = Zip<[1, 2], [true, false]> ⇒ [[1, true], [2, false]]]
type Zip<A extends any[], A2 extends any[], R extends any[] = []> = A extends [
infer F,
...infer O,
]
? A2 extends [infer F2, ...infer O2]
? Zip<O, O2, [...R, [F, F2]]>
: R
: R
04484-medium-istuple [判断 tuple 类型]
type IsTuple<T> = [T] extends [never]
? false
: T extends readonly [infer _F]
? true
: T extends []
? true
: false
04499-medium-chunk [type exp1 = Chunk<[1, 2, 3], 2> ⇒ [[1, 2], [3]]]
type Chunk<
T extends any[],
N extends number,
R extends any[] = [],
R2 extends any[] = [],
C extends any[] = [],
> = T extends [infer F, ...infer O]
? C['length'] extends N
? Chunk<T, N, [...R, R2], [], []>
: Chunk<O, N, R, [...R2, F], [...C, 1]>
: [] extends R2
? [...R]
: [...R, R2]
*04518-medium-fill [fill 函数的类型定义]
type Fill<
T extends unknown[],
N,
Start extends number = 0,
End extends number = T['length'],
S extends any[] = [],
R extends any[] = [],
> = T extends [infer F, ...infer O]
? S['length'] extends Start
? R['length'] extends End
? [...R, F, ...O]
: Fill<O, N, Start, End, S, [...R, N]>
: Fill<O, N, Start, End, [...S, F], [...R, F]>
: R
04803-medium-trim-right [trim-right 的类型定义]
type TrimCharacter3 = ' ' | '\n' | '\t'
type TrimRight<
S extends string,
B extends string = '',
R extends string = '',
> = S extends `${infer F}${infer O}`
? F extends TrimCharacter3
? TrimRight<O, `${B}${F}`, `${R}`>
: TrimRight<O, `${B}${F}`, `${B}${F}`>
: R
05117-medium-without [Without<[1, 2, 4, 1, 5], [1, 2]>; ⇒ [4, 5]]
type Without<T, U, R extends any[] = []> = T extends [infer F, ...infer O]
? U extends [infer FU, ...infer FO]
? Without<Without<T, FU>, FO>
: F extends U
? Without<O, U, R>
: Without<O, U, [...R, F]>
: R
05140-medium-trunc [移除小数点后面的数字]
type Trunc<
S extends string | number,
R extends string = '',
> = `${S}` extends `${infer F}${infer O}`
? F extends '.'
? R
: Trunc<O, `${R}${F}`>
: R
这里讲数字转换为字符串的方式值得注意
05153-medium-indexof [indexof 方法的类型定义]
type IndexOf<T, U, C extends any[] = []> = T extends [infer F, ...infer O]
? Equal<F, U> extends true
? C['length']
: IndexOf<O, U, [...C, 1]>
: -1
05310-medium-join [join 方法的类型定义]
type Join<
T extends any[],
U extends string | number,
R extends string = '',
> = T extends [infer F, ...infer O]
? R extends ''
? Join<O, U, `${R}${F & string}`>
: Join<O, U, `${R}${U}${F & string}`>
: R
05317-medium-lastindexof [lastIndexOf 方法的类型定义]
type LastIndexOf<
T,
U,
L extends any[] = [],
R extends any[] | -1 = -1,
> = T extends [infer F, ...infer O]
? Equal<F, U> extends true
? R extends any[]
? LastIndexOf<O, U, [], [...L, ...R, 1]>
: LastIndexOf<O, U, [], [...L]>
: LastIndexOf<O, U, [...L, 1], R>
: R extends any[]
? R['length']
: R
05360-medium-unique [数组中重复的项目只保留一个]
type UniqueInclude<T, U extends any[]> = U extends [infer F, ...infer O]
? Equal<F, T> extends true
? true
: UniqueInclude<T, O>
: false
type Unique<T, R extends any[] = []> = T extends [infer F, ...infer O]
? UniqueInclude<F, R> extends true
? Unique<O, R>
: Unique<O, [...R, F]>
: R
05821-medium-maptypes [替换对象中值的类型]
type MapTypes<
T extends Object,
R extends {
mapFrom: unknown
mapTo: unknown
},
> = {
[P in keyof T]: T[P] extends R['mapFrom']
? R extends { mapFrom: T[P] }
? R['mapTo']
: never
: T[P]
}
07544-medium-construct-tuple [创建指定长度的数组]
type ConstructTuple<
L extends number,
A extends any[] = [],
> = A['length'] extends L ? A : ConstructTuple<L, [unknown, ...A]>
利用数组进行计数只是一个无奈之举
08640-medium-number-range
type NumberRange<L, H, A extends any[] = [], R = ''> = A['length'] extends L
? NumberRange<L, H, [...A, 1], A['length']>
: A['length'] extends H
? R | A['length']
: NumberRange<L, H, [...A, 1], R | A['length']>
*08767-medium-combination [数组转换成union,然后列出union所有排列组合]
type UnionCombination<T extends string, Y extends string = T> = T extends Y
? T | `${T} ${UnionCombination<Exclude<Y, T>>}`
: never
type ArrToUnion<T, R extends string | never = never> = T extends [
infer F,
...infer O,
]
? ArrToUnion<O, R | (F & string)>
: R
type Combination<T extends any[]> = UnionCombination<ArrToUnion<T>>
08987-medium-subsequence [Subsequence<[1, 2]> ⇒ [] | [1] | [2] | [1, 2]]
type Subsequence<T extends any[], R = []> = T extends [infer F, ...infer O]
? Subsequence<O, [F, ...Subsequence<O>] | R>
: R