ts面试题: 面试题2

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值