31. 计算字符串长度
// 计算字符串的长度,类似于 String#length 。
答案
type test = Str1<"abc123">;
type Str1<T extends string, L extends any[] = []> = T extends `${infer f}${infer b}` ? Str1<b, [...L, f]> : L['length'];
32. 接口添加字段
// 实现一个为接口添加一个新字段的类型。该类型接收三个参数,返回带有新字段的接口类型。
例如:
type Test = { id: '1' }
type Result = AppendToObject<Test, 'value', 4> // expected to be { id: '1', value: 4 }
答案
type AppendToObject<T, K extends string, N,> = {
[P in (keyof T | K)]: P extends keyof T ? T[P] : N
}
33.返回一个正数字符串
Absolute
实现一个接收string,number或bigInt类型参数的Absolute类型,返回一个正数字符串。
例如
type Test = -100;
type Result = Absolute<'-12309'>; // expected to be "100"
答案
type Absolute<T> = T extends (string|number|bigint) ? `${T}` extends `${'-'}${infer F}` ? F: `${T}` :''
34. 字符串转字母联合类型
String to Union
实现一个将接收到的String参数转换为一个字母Union的类型。
例如
type Test = '123';
type Result = StringToUnion<Test>; // expected to be "1" | "2" | "3"
答案
type StringToUnion<T, F extends any[] = []> =
T extends `${infer First}${infer O}` ? StringToUnion<O, [ ...F, First]> : F[number]
35. merge合并两个接口类型
// Merge
// 将两个类型合并成一个类型,第二个类型的键会覆盖第一个类型的键。
// 例如
type foo = {
name: string;
age: string;
}
type coo = {
age: number;
sex: string
}
type Result = Merge<foo,coo>; // expected to be {name: string, age: number, sex: string}
答案
type Merge<T, U> = {
[P in keyof T | keyof U]: P extends keyof U ? U[P] : P extends keyof T? T[P] : never
}
36. 将大小写驼峰写法转换成短横线连接命名法
// KebabCase
// 将camelCase小驼拼写法或pascalcase大驼峰写法(第一个字符是大写的驼峰写法)字符串替换为短横线连接命名法。
// FooBarBaz -> foo-bar-baz
// 例如
type FooBarBaz = KebabCase<"FooBarBaz">
const foobarbaz: FooBarBaz = "foo-bar-baz"
type DoNothing = KebabCase<"do-nothing">
const doNothing: DoNothing = "do-nothing"
答案
type KebabCase<T, S extends string = ''> =
T extends `${infer first}${infer other}` ?
KebabCase<other, `${S}${first extends Lowercase<first> ? '' : '-'}${Lowercase<first>}`>
: S extends `${'-'}${infer O}` ? O : S
37. 获取接口差值属性
// 获取两个接口类型中的差值属性。
type Foo = {
a: string;
b: number;
}
type Bar = {
a: string;
c: boolean
}
type Result1 = Diff<Foo,Bar> // { b: number, c: boolean }
type Result2 = Diff<Bar,Foo> // { b: number, c: boolean }
答案
type Diff<A, B,> = {
[P in Exclude<keyof A | keyof B, keyof A & keyof B>]: P extends keyof A ? A[P] : P extends keyof B ? B[P] : never
}
38. 判断数组中一个元素为真则为真
在类型系统中实现类似于 Python 中 any 函数。类型接收一个数组,如果数组中任一个元素为真,则返回 true,否则返回 false。如果数组为空,返回 false。
// 在类型系统中实现类似于 Python 中 any 函数。类型接收一个数组,如果数组中任一个元素为真,则返回 true,否则返回 false。
// 如果数组为空,返回 false。
// 例如:
type Sample1 = AnyOf<[1, '', false, [], {}]> // expected to be true.
type Sample2 = AnyOf<[0, '', false, [], {}]> // expected to be false.
答案
type Flag<T> = // 判断单个元素是不是为真
T extends '' | 0 | [] | false | never | void | null | undefined ? false // 排除一些空的类型
: T extends object ? keyof T extends never ? false : true : true // 判断是不是非空对象
type AnyOf<T extends any[]> = T extends [infer first, ...infer other] ? Flag<first> extends true ? true : AnyOf<other> : false
type test2 = AnyOf<['']> // 列表中的所有元素都为 False 或等价于 False
type test3 = AnyOf<[1, '', false, [], {}]> // true
type test4 = AnyOf<[false, false]> // false
type test6 = AnyOf<[]> // false
39. 实现IsNever
// 实现一个类型IsNever,它接受输入类型T。如果的类型解析为never,则返回true,否则为false。
// 例如
type A = IsNever<never> // expected to be true
type B = IsNever<undefined> // expected to be false
type C = IsNever<null> // expected to be false
type D = IsNever<[]> // expected to be false
type E = IsNever<number> // expected to be false
答案
type IsNever<T> = [T] extends [never] ? true : false
40. 实现IsUnion判断联合类型 中等
41. 移除映射类型的索引签名 中等
实现RemoveIndexSignature<T>,从对象类型中排除索引签名
// 例如
type Foo = {
[key: string]: any
foo(): void
}
type A = RemoveIndexSignature<Foo> // expected { foo(): void }
答案
type RemoveIndexSignature<T> = {
[P in (keyof T) as (string extends P ? never : P)]: T[P];
};
42. 百分比分析器
// 百分比分析器
// 实现类型 PercentageParser。根据规则 /^(\+|\-)?(\d*)?(\%)?$/ 匹配类型 T。
// 匹配的结果由三部分组成,分别是:[正负号, 数字, 单位],如果没有匹配,则默认是空字符串。
// 例如:
type PString1 = ''
type PString2 = '+85%'
type PString3 = '-85%'
type PString4 = '85%'
type PString5 = '85'
type R1 = PercentageParser<PString1> // expected ['', '', '']
type R2 = PercentageParser<PString2> // expected ["+", "85", "%"]
type R3 = PercentageParser<PString3> // expected ["-", "85", "%"]
type R4 = PercentageParser<PString4> // expected ["", "85", "%"]
type R5 = PercentageParser<PString5> // expected ["", "85", ""]
答案
type PercentageParser<S, U extends string[] = ['', '', '']> = S extends `${infer first}${infer other}` ?
first extends '+' | '-' ? PercentageParser<other, [first, U[1], U[2]]> :
first extends '%' ? PercentageParser<other, [U[0], U[1], first]> : PercentageParser<other, [U[0], `${U[1]}${first}`, U[2]]>
: U
43. 从字符串中剔除指定字符
// Drop Char
// 从字符串中剔除指定字符。
// 例如:
type Butterfly = DropChar<' b u t t e r f l y ! ', ' '> // 'butterfly!'
答案
type DropChar<T, K extends string> = T extends `${infer U}${K}${infer M}` ? DropChar<`${U}${M}`, K> : T
44.数字减去1 中等
// MinusOne
// 给定一个正整数作为类型的参数,要求返回的类型是该数字减 1。
例如:
type Zero = MinusOne<1> // 0
type FiftyFour = MinusOne<55> // 54
答案
type MinusOne<N extends number, U extends any[] = []>
= U['length'] extends N ? (U extends [infer first, ...infer other] ? other['length'] : never) : MinusOne<N, [...U, 0]>
45. 从接口中挑选值和指定类型相同的组成接口
// PickByType
// 从T中,选择一组类型可分配给U的属性。
// 例如
type OnlyBoolean = PickByType<{
name: string
count: number
isReadonly: boolean
isEnable: boolean
}, boolean> // { isReadonly: boolean; isEnable: boolean; }
答案
type PickByType<T, K> = {
[P in keyof T as T[P] extends K ? P : never]: T[P]
}
46. 实现字符串的startWith类型和EndsWith类型
//starwidth
// 实现StartsWith<T, U>,接收两个string类型参数,然后判断T是否以U开头,根据结果返回true或false
// 例如:
type a = StartsWith<'abc', 'ac'> // expected to be false
type b = StartsWith<'abc', 'ab'> // expected to be true
type c = StartsWith<'abc', 'abcd'> // expected to be false
//endwidth
// 实现EndsWith<T, U>,接收两个string类型参数,然后判断T是否以U结尾,根据结果返回true或false
// 例如:
type a = EndsWith<'abc', 'bc'> // expected to be true
type b = EndsWith<'abc', 'abc'> // expected to be true
type c = EndsWith<'abc', 'd'> // expected to be false
答案
type StartsWith<T, F extends string> = T extends `${F}${infer B}` ? true : false
type EndsWith<T, F extends string> = T extends `${infer B}${F}` ? true : false
47. 指定接口部分字段为可选 和 必选
// 可选
// PartialByKeys
// 实现一个通用的PartialByKeys<T, K>,它接收两个类型参数T和K。
// K指定应设置为可选的T的属性集。当没有提供K时,它就和普通的Partial<T>一样使所有属性都是可选的。
// 例如:
interface User {
name: string
age: number
address: string
}
type UserPartialName = PartialByKeys<User, 'name'> // { name?:string; age:number; address:string }
// 必选
// RequiredByKeys
// 实现一个通用的RequiredByKeys<T, K>,它接收两个类型参数T和K。
// K指定应设为必选的T的属性集。当没有提供K时,它就和普通的Required<T>一样使所有的属性成为必选的。
// 例如:
interface User {
name?: string
age?: number
address?: string
}
type UserRequiredName = RequiredByKeys<User, 'name'> // { name: string; age?: number; address?: string }
答案
// 可选
type IntersectionToObj<T> = {
[K in keyof T]: T[K]
}
type PartialByKeys<T , K = any> = IntersectionToObj<{
[P in keyof T as P extends K ? P : never]?: T[P]
} & {
[P in Exclude<keyof T, K>]: T[P]
}>
// 必选
type MapObj<T> = {
[P in keyof T]: T[P]
}
type RequiredByKeys<T, K extends string> = MapObj<{
[P in keyof T as P extends K ? never : P]?: T[P]
} & Required<{
[P in keyof User as P extends 'name' ? P : never]: User[P]
}>>
48. 接口属性变成非只读
// Mutable
// 实现一个通用的类型 Mutable<T>,使类型 T 的全部属性可变(非只读)。
// 例如:
interface Todo {
readonly title: string
readonly description: string
readonly completed: boolean
}
type MutableTodo = Mutable<Todo> // { title: string; description: string; completed: boolean; }
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
答案
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
49. 获取接口的键和值 中等
// ObjectEntries
// 从T中,选择一组类型不可分配给U的属性。
// 例如
interface Model {
name: string;
age: number;
locations: string[] | null;
}
type modelEntries = ObjectEntries<Model> // ['name', string] | ['age', number] | ['locations', string[] | null];
答案
type ObjectEntries<T> = {
[P in keyof T]: [P, T[P]]
}[keyof T]
50. 实现数组的Shift
// Shift
// 实现Array.shift的类型版本
// 例如
type Result = Shift<[3, 2, 1]> // [2, 1]
答案
type Shift<T> = T extends [infer first, ...infer other] ? other : T
51. 从接口中排除值为某个类型的键
// OmitByType
// 从T中,选择一组类型不可分配给U的属性。
// 例如
type OmitBoolean = OmitByType<{
name: string
count: number
isReadonly: boolean
isEnable: boolean
}, boolean> // { name: string; count: number }
答案
type OmitByType<T, K> = {
[P in keyof T as T[P] extends K ? never : P]: T[P]
}
52. 元组嵌套成对象
// 给定一个只包含字符串类型的元组类型T和一个类型U,递归地构建一个对象。
type a = TupleToNestedObject<['a'], string> // {a: string}
type b = TupleToNestedObject<['a', 'b'], number> // {a: {b: number}}
type c = TupleToNestedObject<[], boolean> // boolean. 如果元组为空,则只返回U类型
答案
type TupleToNestedObject<T extends any[], K , R extends any = {}> =
T extends [] ? K
: T extends [...infer other,infer last] ? (last extends string ? TupleToNestedObject<other, {[P in last]: K}> : never)
: never
53. 翻转数组
// Reverse
// 实现类型版本的数组反转 Array.reverse
// 例如:
type a = Reverse<['a', 'b']> // ['b', 'a']
type b = Reverse<['a', 'b', 'c']> // ['c', 'b', 'a']
答案
type Reverse<T extends any[], R extends any[] = [], L extends number = T['length']> =
R['length'] extends L ? R
: T extends [...infer other, infer last] ? Reverse<other, [...R, last], L> : R
54. 翻转函数参数
// 翻转参数
// 实现lodash的_.flip的类型版本。
// Type FlipArguments<T>需要函数类型T,并返回一个新的函数类型,该函数类型的返回类型与T相同,但参数相反。
// 例如
type Flipped = FlipArguments<(arg0: string, arg1: number, arg2: boolean) => void>
// (arg0: boolean, arg1: number, arg2: string) => void
答案
type Reverse<T extends any[], R extends any[] = [], L extends number = T['length']> =
R['length'] extends L ? R
: T extends [...infer other, infer last] ? Reverse<other, [...R, last], L> : R
type FlipArguments<T> = T extends (...arg: infer G) => infer R ? (...x: Reverse<G>) => R
: never
55. 扁平化多维数组
// 扁平深度
// 递归地将数组展平到深度次。
// 例如
type a = FlattenDepth<[1, 2, [3, 4], [[[5]]]], 2> // [1, 2, 3, 4, [5]]. flattern 2 times
type b2 = FlattenDepth<[1, 2, [3, 4], [[[5]]]], 3> // [1, 2, 3, 4, [[5]]]. Depth defaults to be 1
type c = FlattenDepth<[1, 2, [], [[[5]]]]>
答案
// 单层扁平化
type Flatten<A extends any[], R extends any[] = []> =
A extends [infer first, ...infer other] ? first extends [...infer B] | [] ? Flatten<other, [...R, ...first]>
: Flatten<other, [...R, first]> : R
type FlattenDepth<A extends any[], C extends number = 1, R extends any[] = []> =
R['length'] extends C ? A :
FlattenDepth<Flatten<A>, C, [...R, '']>
56. 得到BEM样式字符串
// BEM样式字符串
// 块、元素、修饰符方法论(BEM)是CSS中常用的类命名约定。
// 例如,块组件将表示为btn,依赖于块的元素将表示为btn_price,更改块样式的修饰符将表示为btn-big或btn_price-warning。
// 实现BEM<B,E,M>,根据这三个参数生成字符串并集。其中B是字符串文字,E和M是字符串数组(可以为空)
// 块 .header、.main-nav
// 元素 .header__logo、.main-nav__item
// 修饰符 .header--dark、.main-nav__item--active
答案
type test = BEM<'btn', ['price'], ['warning']>
type test2 = BEM<'main-nav', ['title', 'item'], ['large', 'warning']>
type GetStr<T, I extends string = '', R extends string = '', > =
T extends [] ? R
: T extends [infer first, ...infer other] ? (first extends string ? GetStr<other, I, `${R}${I}${first}`> : R)
: R
type BEM<B extends string, E extends string[], M extends string[]> = `${B}${GetStr<E, '__'>}${GetStr<M, '--'>}`
57. 接口属性和键对调
// 实现仅翻转对象的类型。示例:
// 不需要支持嵌套的对象和不能作为对象键(如数组)的值
type test1 = Flip<{ a: "x", b: "y", c: "z" }>; // {x: 'a', y: 'b', z: 'c'}
type test2 = Flip<{ a: 1, b: 2, c: 3 }>; // {1: 'a', 2: 'b', 3: 'c'}
type test3 = Flip<{ a: false, b: true }>; // {false: 'a', true: 'b'}
答案
type Flip<T> = {
[P in keyof T as T[P] extends string | number ? T[P] : T[P] extends boolean ? `${T[P]}`: never] : P
}
58. 返回某个位置的斐波那契序列数字
// 实现一个通用的Fibonacci<T>,它取一个数字T并返回它对应的Fibonaci数。
// 顺序开始:1、1、2、3、5、8、13、21、34、55、89、144。。。
// 例如
type Result0 = Fibonacci<1> // 1
type Result00 = Fibonacci<2> // 1
type Result1 = Fibonacci<3> // 2
type Result2 = Fibonacci<8> // 21
答案
// 方式一: 只能算到17位 (根据前两位来计算,知道数组长度符合要求)
// type Result3 = Fibonacci<17> // 6765
// type Fibonacci<N extends number, A extends any[] = [1, 1]> = N extends 1 ? 1 :
// A['length'] extends N ? (A extends [...infer A, infer B] ? B : never) : Fibonacci<N, [...A, Target<A>]>
// type Target<T extends number[]> =
// T extends [...infer other, infer one, infer two] ? one extends number ? two extends number
// ? [...Node2<one>, ...Node2<two>]['length'] : never : never : never
// type Node2<N extends number, L extends any[] = []> = L['length'] extends N ? L : Node2<N, [...L, '']>
// 方式二: 只能算到20位
// type Result3 = Fibonacci<20> // 6765
type Fibonacci<T extends number, CurrentIndex extends any[] = [1], Prev extends any[] = [], Current extends any[] = [1]> = CurrentIndex['length'] extends T
? Current['length']
: Fibonacci<T, [...CurrentIndex, 1], Current, [...Prev, ...Current]>
59. 数字比大小
// Greater Than
// 在这个挑战中,您应该实现一个类型GreaterThan<T,U>,如T>U
// 负数不需要考虑。
// 例如
type test1 = GreaterThan<2, 1> //should be true
type test2 = GreaterThan<1, 1> //should be false
type test3 = GreaterThan<10, 100> //should be false
type test4 = GreaterThan<111, 11> //should be true
type test5 = GreaterThan<11111, 111> //should be true
答案
type GreaterThan<N extends number, M extends number,L extends any[] = []> =
L['length'] extends N | M ? L['length'] extends N ? false : true : GreaterThan<N, M, [...L, '']>
60. 两个元组一一对应合成二位数组
// 在这个挑战中,你应该实现一个类型Zip<T,U>,T和U必须是元组
type exp = Zip<[1, 2], [true, false]> // expected to be [[1, true], [2, false]]
答案
type Zip<T, U, R extends any[] = []> =
T extends [infer first, ...infer other] ? U extends [infer firstU, ...infer otherU] ? Zip<other, otherU, [...R, [first, firstU]]> : never:R
61. 区分元组IsTuple
// IsTuple
// 实现一个类型IsTuple,它接受一个输入类型T并返回T是否为元组类型。
// 例如
type case1 = IsTuple<[number]> // true
type case2 = IsTuple<readonly [number]> // true
type case22 = IsTuple< [number, string]> // true
type case3 = IsTuple<number[]> // false
答案
type IsTuple<T> = [T] extends [never] ? false
: T extends any[] | readonly any[] ? T[number] extends number ? (T extends [number] | readonly [number] ? true : false) : true
: false
// 区分数组和元组
type shuzu = number[]
type yuanzu = [number]
type shuzu1 = shuzu[number] // number
type yuanzu1 = yuanzu[number] // number
type shuzu2 = keyof shuzu // keyof shuzu
type yuanzu2 = keyof yuanzu // keyof yuanzu
type shuzu3 = shuzu extends number[] ? true : false // true
type yuanzu3 = yuanzu extends number[] ? true : false // true
type shuzu4 = shuzu extends [number] ? true : false // false
type yuanzu4 = yuanzu extends [number] ? true : false // true
type shuzu5 = number[] extends number[] ? true : false // true
type yuanzu5 = [number] extends number[] ? true : false // true
62. 指定维度分割数组
// Chunk
// 你认识lodash吗?Chunk是其中一个非常有用的函数,现在让我们实现它。Chunk<T,N>接受两个必需的类型参数,T必须是元组,N必须是整数>=1
type exp1 = Chunk<[1, 2, 3], 2> // expected to be [[1, 2], [3]]
type exp2 = Chunk<[1, 2, 3], 4> // expected to be [[1, 2, 3]]
type exp22 = Chunk<[1, 2, 3, 4], 3> // expected to be [[1, 2, 3], [4]]
type exp222 = Chunk<[1, 2, 3], 3> // expected to be [[1, 2, 3], [4]]
type exp3 = Chunk<[1, 2, 3], 1> // expected to be [[1], [2], [3]]
答案
type Chunk<T, N, Current extends any[] = [], Target extends any[] = []> =
T extends [] ? Target : // 结束时
T extends [infer first, ...infer other] ?
other extends [] ?
Chunk<[], N, [], Current['length'] extends N ? [...Target,Current,[ first]] : [...Target,[...Current, first]]> // 最后一项
: Current['length'] extends N ? Chunk<other, N, [first], [...Target, Current]> : Chunk<other, N, [...Current,first], Target>
: Target
63. 填充数组指定区域片段
// Fill是一个常见的JavaScript函数,现在让我们用类型来实现它。
// 填充<T,N,开始?,终止如您所见,Fill接受四种类型的参数,其中T和N是必需参数,
// Start和End是可选参数。这些参数的要求是:T必须是元组,N可以是任何类型的值,Start和End必须是大于或等于0的整数。
// 为了模拟真实的函数,测试中可能包含一些边界条件,希望您能喜欢:)
type exp = Fill<[1, 2, 3], 0> // expected to be [0, 0, 0]
type exp2 = Fill<[1, 2, 3, 4], 0, 1, 6> // expected to be [0, 0, 0, 0]
type exp3 = Fill<[1, 2, 3, 4], 0, 1, 4> // expected to be [0, 0, 0, 0]
type exp4 = Fill<[1, 2, 3, 4], 0, 2, 4> // expected to be [1, 0, 0, 0]
type exp5 = Fill<[1, 2, 3, 4], 0, 1, 1> // expected to be [0, 2, 3, 4]
答案
type Fill<T extends any[], N extends number, Start extends number = 1, End extends number = T['length'],
len extends any[] = [''],Result extends any[] = [], Flag extends boolean = false, > = //
T extends [] ? Result :
T extends [infer first, ...infer other] ?
Fill<other, N, Start, End, [...len, ''],
[...Result,
len['length'] extends Start ? N : Flag extends true ? N : first // len['length'] extends End ? first :
],
len['length'] extends Start ? len['length'] extends End ? false : true : len['length'] extends End ? false : Flag
>: never
64. 去除数组种指定元素
// 去除数组指定元素
// 实现一个像 Lodash.without 函数一样的泛型 Without<T, U>,它接收数组类型的 T 和数字或数组类型的 U 为参数,会返回一个去除 U 中元素的数组 T。
// 例如:
type Res = Without<[1, 2], 1>; // expected to be [2]
type Res1 = Without<[4, 1, 2, 4, 1, 5], [1, 2]>; // expected to be [4, 5]
type Res2 = Without<[2, 3, 2, 3, 2, 3, 2, 3], [2, 3]>; // expected to be []
答案
type Without<T extends any[], U extends any[] | number, Temp extends any[] = [],>=
T extends [] ? Temp :
T extends [infer first, ...infer other] ?
Without<other, U, first extends (U extends number[] ? U[number] : U ) | Temp[number] ? [...Temp] : [...Temp, first] > : never
65. 去掉字符串右边的空白字符串
// Trim Right
// 实现 TrimRight<T> ,它接收确定的字符串类型并返回一个新的字符串,其中新返回的字符串删除了原字符串结尾的空白字符串。
// 例如
type Trimed = TrimRight<' Hello World '> // 应推导出 ' Hello World'
答案
type TrimRight<T> = T extends `${infer S}${' '}` ? TrimRight<S> : T
66. 截取字符串数字的整数部分
// Trunc
// 实现Math.trunc的类型版本,它采用字符串或数字,并通过删除任何小数位数来返回数字的整数部分。
// 例如
// type A = Trunc<12.34> // 12
// type B = Trunc<-4.9> // -4
// type C = Trunc<-0.12345>
答案
type Trunc<T> = T extends number ? `${T}` extends `${infer Integer}.${infer _}` ? Integer : `${T}` : never;
67. 从数组中查找某个元素的索引
// IndexOf
// 实现Array.indexOf的类型版本。indexOf,indexOf<T,U>获取数组T,任意U,并返回数组T中第一个U的索引。
type Res = IndexOf<[1, 2, 3], 2>; // expected to be 1
type Res1 = IndexOf<[2,6, 3,8,4,1,7, 3,9], 3>; // expected to be 2
type Res2 = IndexOf<[0, 0, 0], 2>; // expected to be -1
答案
type Loop<T, K, Temp extends any[] = []> =
T extends [infer first, ...infer other] ? first extends K ? [...Temp, first] : Loop<other, K, [...Temp, first]> : -1
type IndexOf<T, K, Temp = Loop<T, K>> = Temp extends [infer first, ...infer other] ? other['length'] : Temp
68. 用指定字符拼接数组
// Join
// 实现Array.join的类型版本,join<T,U>获取数组T、字符串或数字U,并返回U缝合的数组T。
type Res = Join<["a", "p", "p", "l", "e"], "-">; // expected to be 'a-p-p-l-e'
type Res1 = Join<["Hello", "World"], " ">; // expected to be 'Hello World'
type Res2 = Join<["2", "2", "2"], 1>; // expected to be '21212'
type Res3 = Join<["o"], "u">; // expected to be 'o'
答案
type Join<T, U extends string | number, Temp extends string = ''> =
T extends [] ? (Temp extends `${U}${infer F}` ? F : Temp) :
T extends [infer first extends string, ...infer other] ? Join<other, U, `${Temp}${U}${first}`> : never
69. 从数组后查找某个字符对应的索引
// LastIndexOf
// 实现类型版本的 Array.lastIndexOf, LastIndexOf<T, U> 接受数组 T, any 类型 U, 如果 U 存在于 T 中,
// 返回 U 在数组 T 中最后一个位置的索引, 不存在则返回 -1
// For example:
type Res1 = LastIndexOf<[1, 2, 3, 2, 1], 2> // 3
type Res2 = LastIndexOf<[0, 0, 0], 2> // -1
答案
type Loop<T, I, Temp extends any[] = []> =
T extends [...infer other, infer last] ? last extends I ? [last, ...Temp] : Loop<other, I, [last, ...Temp]> : []
type LastIndexOf<T, I, R extends any[] = Loop<T, I>> = R extends [] ? -1 :
T extends [...infer B, ...R] ? B['length'] extends 0 ? -1 : B['length'] : -1
70. 数组去重 中等
特别说明
// 对于包含 unknown 或 any 的情况,TypeScript 类型系统无法直接处理
type test444 = Equal<unknown, any> // 永远是true
// Unique
// 实现类型版本的 Lodash.uniq 方法, Unique 接收数组类型 T, 返回去重后的数组类型.
type Res = Unique<[1, 1, 2, 2, 3, 3]>; // expected to be [1, 2, 3]
type Res1 = Unique<[1, 2, 3, 4, 4, 5, 6, 7]>; // expected to be [1, 2, 3, 4, 5, 6, 7]
type Res2 = Unique<[1, "a", 2, "b", 2, "a"]>; // expected to be [1, "a", 2, "b"]
type Res3 = Unique<[string, number, 1, "a", 1, string, 2, "b", 2, number]>; // expected to be [string, number, 1, "a", 2, "b"]
type Res4 = Unique<[unknown, unknown, any, any, never, never]>; // expected to be [unknown, any, never]
答案
type Equal<T, U> =
T extends U ? (
U extends T ? true : false
) : false;
type Exist<T, U> = T extends [] ? false : // 判断存在
T extends [infer first, ...infer other] ? Equal<first, U> extends true ? true : Exist<other, U> : false
type Unique<T, Temp extends any[] = []> =
T extends [] ? Temp
: T extends [infer first, ...infer other] ?
Exist<Temp, first> extends true ? Unique<other, [...Temp]> : Unique<other, [...Temp, first]>
: never
71. 构造自动长度的元组
// 构造一个给定长度的元组。
// 例如
type result = ConstructTuple<2> // 期望得到 [unknown, unkonwn]
答案
type ConstructTuple<T, R extends any[] = []> =
R['length'] extends T ? R : ConstructTuple<T, [...R, unknown]>
72. 根据数字范围生成范围内所有元素的联合
// Sometimes we want to limit the range of numbers... For examples.
type result0 = NumberRange<2 , 9> // | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
答案
type NumberRange<Start, End, L extends any[] = [''], R extends number[] = [], Flag extends boolean = false > =
L['length'] extends End
? [...R, L['length']]
: NumberRange<Start, End, [...L, ''],
Flag extends true ? [...R, L['length']] : L['length'] extends Start ? [...R, L['length']] : [...R],
L['length'] extends Start? true : Flag
>
73. 检查字符串中是否有相同的字符
// CheckRepeatedChars
// 判断一个string类型中是否有相同的字符
type test1 = CheckRepeatedChars<'abc'> // false
type test2 = CheckRepeatedChars<'aba'> // true
答案
type has<S, K> =
S extends `${infer first}${infer other}` ? first extends K ? true : other extends '' ? false : has<other, K> : false
type CheckRepeatedChars<S> =
S extends `${infer first}${infer other}` ? has<other, first> extends true ? true : other extends '' ? false : CheckRepeatedChars<other> : false
74. 找到字符串中第一个不重复字符的索引
// FirstUniqueCharIndex
// 给定一个字符串s,找到其中第一个不重复的字符并返回其索引。如果不存在,则返回-1。(灵感来自leetcode 387)
type test1 = CheckChars<"leetcode">// 0
type test2 = CheckChars<"loveleetcode"> // 2
type test3 = CheckChars<"aabb">// -1
答案
type hasStr<S, K> =
S extends `${infer first}${infer other}` ? first extends K ? true : other extends '' ? false : hasStr<other, K> : false
type IsRepeatStr<List, K> = List extends [] ? false
:List extends [infer first, ...infer other] ? first extends K ? true : IsRepeatStr<other, K> : never
type CheckChars<S, len extends any[] = [''], List extends any[] = ['']> =
S extends `${infer first}${infer other}`
? IsRepeatStr<List, first> extends true ? CheckChars<other, [...len, '']> :
hasStr<other, first> extends true ? CheckChars<other, [...len, ''], [...List, first]> : len extends [infer A, ...infer B] ? B['length'] : -1
: -1
75. 将URL参数字符串解析为联合类型
// Parse URL Params
// 您需要实现一个类型级解析器来将URL参数字符串解析为Union。
type a1 = ParseUrlParams<':id'> // id
type a2 = ParseUrlParams<'posts/:id'> // id
type a3 = ParseUrlParams<'posts/:id/:user'> // id | user
答案
type ParseUrlParams<S, Flag extends boolean = false, List extends any[] = [], current extends string = '' > =
S extends `${infer first}${infer other}`
? first extends ':'
? ParseUrlParams<other, true, List>
: first extends "/" | ''
? ParseUrlParams<other, false, current extends '' ? List :[...List, current]>
:ParseUrlParams<other, Flag, List, Flag extends true ? `${current}${first}` : current>
: [...List, current][number]
76. 获取数组的中间元素
// 获取数组的中间元素
// 通过实现一个 GetMiddleElement 方法,获取数组的中间元素,用数组表示
// 如果数组的长度为奇数,则返回中间一个元素 如果数组的长度为偶数,则返回中间两个元素
type simple1 = GetMiddleElement<[1, 2, 3, 4, 5]> // 返回 [3]
type simple2 = GetMiddleElement<[1, 2, 3, 4, 5, 6]> // 返回 [3, 4]
答案
type GetMiddleElement<T> =
T extends [infer first, ...infer other, infer last]
? other['length'] extends 2
? other
: other['length'] extends 1
? other
: other['length'] extends 0
? [first, last]
: GetMiddleElement<other>
: never
77. 找到数组中只出现过一次的元素
// 找出目标数组中只出现过一次的元素 中等
// 找出目标数组中只出现过一次的元素。例如:输入[1,2,2,3,3,4,5,6,6,6],输出[1,4,5]
type test = FindOnce<[1,2,2,3,3,4,5,6,6,6]> // [1,4,5]
答案
type find<T, K> = T extends [infer first, ...infer other] ? first extends K ? true : find<other, K> : false
type FindOnce<T, Result extends any[] = [], Exit extends any[] = [] > =
T extends [infer first, ...infer other]
? find<other, first> extends true
? FindOnce<other, Result, [...Exit, first]>
: first extends Exit[number]
? FindOnce<other, Result, Exit>
: FindOnce<other, [...Result, first], Exit>
: Result
78. 判断是否为整数 中等
// 整数
// 请完成类型 Integer<T>,类型 T 继承于 number,如果 T 是一个整数则返回它,否则返回 never。
答案
type Integer<T> = T extends bigint ? T: never