国外前端会考察哪些问题?js函数、系统设计、TS类型体操的用法,大大拓宽了我的眼界,去思考和实战更加相关的问题吧,还有一个Type-challenges,经常更新一个新的Type实现:TypeScript 类型体操姿势合集
TypeScript类型体操
这一部分很有意思,你写过一遍之后,对于TS里怎么用这些方法更加得心应手
1. implement Partial<T>
题目
Partial<T> returns a type whichs represents all subsets of type T.
Please implement MyPartial<T> by yourself.
1 | type Foo = { |
答案
找到键的索引,全部用?转化为可选
1 | type MyPartial<T> = { |
keyof 索引查询 对应任何类型 T,keyof T的结果为该类型上所有公有属性key的联合:
1 | interface Eg1 { |
2. implement Required<T>
题目
As the opposite of Partial, Required<T> sets all properties of T to required.
Please implement MyRequired<T> by yourself.
1 | // all properties are optional |
答案
找到键的索引,全部用-?转化为必选
1 | type MyPartial<T> = { |
3. implement Readonly<T>
题目
Readonly<T> returns a type that sets all properties of T to readonly.
Pleaes implement MyReadonly<T> by yourself.
1 | type Foo = { |
答案
找到键的索引,全部用readonly转化为只读属性,keyof 索引类型查询操作符。 对于任何类型 T, keyof T的结果为 T上已知的公共属性名的联合。T[P] 索引访问操作符。根据属性名获得对应类型。
1 | type MyReadonly<T> = { |
4. implement Record<K, V>
题目
Record<K, V> returns an object type with keys of K and values of V.
Please implement MyRecord<K, V> by yourself.
Notice that property key could only be number | string | symbol.
1 | type Key = 'a' | 'b' | 'c' |
答案
这个稍微复杂一些,需要用extends表明键的类型
1 | type MyRecord <K extends string | number | symbol, V> = { |
5. implement Pick<T, K>
题目
Pick<T, K>, as the name implies, returns a new type by picking properties in K from T.
Please implement MyPick<T, K> by yourself.
1 | type Foo = { |
答案
同样,需要用extends表明键的范围
1 | type MyPick<T, K extends keyof T> = { |
6. implement Omit<T, K>
题目
Omit<T, K> returns a new type by picking the properties in T but not in K.
Please implement MyOmit<T, K> by yourself.
1 | type Foo = { |
答案
需要用extends结合三目判断符进行判断,将找不到的键名赋值为never
Here is documentation about remapping: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#key-remapping-via-as
1 | type MyOmit<T, K extends keyof any> = { |
7. implement Exclude<T, E>
题目
Exclude<T, K> returns a type by removing from T the union members that are assignable to K.
Please implement MyExclude<T, K> by yourself.
1 | type Foo = 'a' | 'b' | 'c' |
答案
需要用extends结合三目判断符进行判断,将找不到的键名赋值为never
1 | type MyExclude<T, E> = T extends E ? never : T |
8. implement Extract<T, U>
题目
As the opposite of Exclude, Extract<T, U> returns a type by extracting union members from T that are assignable to U.
Please implement MyExtract<T, U> by yourself.
1 | type Foo = 'a' | 'b' | 'c' |
答案
需要用extends结合三目判断符进行判断,将找不到的键名赋值为never
1 | type MyExtract<T, U> = T extends U ? T : never |
9. implement NonNullable<T>
题目
NonNullable<T> returns a type by excluding null and undefined from T.
Please implement MyNonNullable<T> by yourself.
1 | type Foo = 'a' | 'b' | null | undefined |
答案
需要用extends结合三目判断符进行判断,将找不到的键名赋值为never
1 | type MyNonNullable<T> = T extends(null | undefined) ? never : T |
10. implement Parameters<T>
题目
For function type T, Parameters<T> returns a tuple type from the types of its parameters.
Please implement MyParameters<T> by yourself.
1 | type Foo = (a: string, b: number, c: boolean) => string |
答案
需要用infers将输入参数提取出来,后面需要补充三目判断符做兜底
1 | type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never; |
11. implement ConstructorParameters<T>
题目
Parameters handles function type. Similarly, ConstructorParameters<T> is meant for class, it returns a tuple type from the types of a constructor function T.
Please implement MyConstructorParameters<T> by yourself.
1 | class Foo { |
答案
需要用infers将输入参数提取出来,后面需要补充三目判断符做兜底
1 | type MyConstructorParameters<T extends new (...args: any) => any> = |
12. implement ReturnType<T>
题目
Similar to Parameters, ReturnType<T>, as the name says itself, returns the return type of function type T.
Please implement MyReturnType<T> by yourself.
1 | type Foo = () => {a: string} |
答案
需要用infers将结果提取出来,后面需要补充三目判断符做兜底
1 | type MyReturnType<T extends (...args: any[]) => any> = |
13. implement InstanceType<T>
题目
For a constructor function type T, InstanceType<T> returns the instance type.
Please implement MyInstanceType<T> by yourself.
1 | class Foo {} |
答案
需要用infers将结果提取出来,后面需要补充三目判断符做兜底
1 | /** |
14. implement ThisParameterType<T>
题目
For a function type T, ThisParameterType<T> extracts the this type. If this is not set, unknown is used.
Please implement MyThisParameterType<T> by yourself.
1 | function Foo(this: {a: string}) {} |
答案
需要用infers将第一个输入参数提取出来,后面需要补充三目判断符做兜底
1 | type MyThisParameterType<T extends (...args: any[]) => any> = |
Sometimes problem is easier than you thought. The question wants to get the ‘this ‘ parameter type, just return this type.
15. implement OmitThisParameter<T>
题目
When Function.prototype.bind() is used, the returned function has a bound this. OmitThisParameter<T> could be used to type this.
Please implement MyOmitThisParameter<T> by yourself.
1 | function foo(this: {a: string}) {} |
答案
需要用infers将第一个输入参数提取出来,后面需要补充三目判断符做兜底
1 | type MyOmitThisParameter<T extends (...args: any[]) => any> = |
16. implement FirstChar<T>
题目
Please implement FirstChar<T> to get the first character of a string.
1 | type A = FirstChar<'BFE'> // 'B' |
答案
需要用infers将参数首字母提取出来,后面需要补充三目判断符做兜底
1 | type FirstChar<T extends string> = T extends `${infer S}${any}` ? S : never |
17. implement LastChar<T>
题目
Similar to FirstChar, please implment LastChar<T> to get the last character.
1 | type A = LastChar<'BFE'> // 'E' |
答案
需要用infers将参数首字母提取出来,后面需要补充三目判断符做兜底,递归调用至最后一个字母
1 | type LastChar<T extends string> = T extends `${infer P}${infer S}` ? (S extends '' ? P : LastChar<S>) : never |
18. implement TupleToUnion<T>
题目
Given a tuple type, implement TupleToUnion<T> to get a union type from it.
1 | type Foo = [string, number, boolean] |
答案
需要用数字索引将数组每一个参数提取出来
1 | type TupleToUnion<T extends any[]> = T[number] |
也可以利用数组递归调用,后面需要补充三目判断符做兜底
1 | type TupleToUnion<T extends any[]> = T extends [ |
19. implement FirstItem<T>
题目
Similar to 16. FirstChar, please implement FirstItem<T> to obtain first item of a tuple type.
1 | type A = FirstItem<[string, number, boolean]> // string |
答案
需要用数字索引将数组第一个参数提取出来,后面需要补充三目判断符做兜底
1 | type FirstItem<T extends any[]> = T[0] extends undefined ? never : T[0] |
20. implement IsNever<T>
题目
Please implement a utility type IsNever<T> which returns true if T is never and false otherwise.
1 | type A = IsNever<never> // true |
答案
需要用将数组never提取出来进行判断,因为没有类型extends never
1 | type IsNever<T> = [T] extends [never] ? true : false |
21. implement LastItem<T>
题目
Similar to 19. FirstItem, please implement LastItem<T> to obtain last item of a tuple type.
1 | type A = LastItem<[string, number, boolean]> // boolean |
答案
需要用将数组最后一个参数提取出来,后面需要补充三目判断符做兜底
1 | type LastItem<T extends any[]> = T extends [...any[], infer P] ? P : never |
22. implement StringToTuple<T>
题目
Given a string literal type, please implement StringToTuple<T> to genrate a tuple type by spreading each characters.
1 | type A = StringToTuple<'BFE.dev'> // ['B', 'F', 'E', '.', 'd', 'e','v'] |
答案
需要用将字符串第一个字母提取出来然后递归调用转化为数组,后面需要补充三目判断符做兜底
1 | type StringToTuple<T extends string> = |
23. implement LengthOfTuple<T>
题目
Here is an easy problem, please implement LengthOfTuple<T> to return the length of tuple.
1 | type A = LengthOfTuple<['B', 'F', 'E']> // 3 |
答案
需要用T[‘length’]方法求得数组长度
1 | type LengthOfTuple<T extends any[]> = T['length'] |
24. implement LengthOfString<T>
题目
Implement LengthOfString<T> to return the length of a string.
1 | type A = LengthOfString<'BFE.dev'> // 7 |
答案
结合字符串转数组和计算数组长度计算字符串长度
1 | type StringToTuple<T extends string> = |
25. implement UnwrapPromise<T>
题目
Implement UnwrapPromise<T> to return the resolved type of a promise.
1 | type A = UnwrapPromise<Promise<string>> // string |
答案
结合字符串转数组和计算数组长度计算字符串长度
1 | type UnwrapPromise<T> = T extends Promise<infer U> ? U : never |
26. implement ReverseTuple<T>
题目
Implement ReverseTuple<T> to reverse a tuple type.
1 | type A = ReverseTuple<[string, number, boolean]> // [boolean, number, string] |
答案
递反转原先的数组
1 | type ReverseTuple<T extends any[]> = |
27. implement Flat<T>
题目
Implement Flat<T> to flatten a tuple type.
1 | type A = Flat<[1,2,3]> // [1,2,3] |
答案
从左到右依次递归展开
1 | type Flat<T extends any[]> = |
28. implement IsEmptyType<T>
题目
Implement IsEmptyType<T> to check if T is empty type {}.
1 | type A = IsEmptyType<string> // false |
答案
确认是对象且没有键返回true,否则为false
1 | type IsEmptyType<T> = number extends T |
29. implement Shift<T>
题目
Implement Shift<T> to shift the first item of a tuple type.
1 | type A = Shift<[1,2,3]> // [2,3] |
答案
把数组第一个元素删去,后面需要补充三目判断符做兜底
1 | type Shift<T extends any[]> = T extends [any, ...infer R] ? [...R] : [] |
30. implement IsAny<T>
题目
Implement IsAny<T> to check against any.
1 | type A = IsAny<string> // false |
答案
利用T & any = any的性质且任意类型extends any的性质判断
1 | type IsAny<T> = false extends true & T ? true : false |
31. implement Push<T, I>
题目
Implement Push<T, I> to return a new type by pushing new type into tuple type.
1 | type A = Push<[1,2,3], 4> // [2,3] |
答案
拼接数组与新的类型
1 | type Push<T extends any[], I> = T extends [...infer P] ? [...P, I] : [I] |
或者直接用展开运算符
1 | type Push<T extends any[], I> = [...T, I] |
32. implement RepeatString<T, C>
题目
Similar to String.prototype.repeat(), implement RepeatString<T, C> to create a new type by repeating string T for C times.
1 | type A = RepeatString<'a', 3> // 'aaa' |
答案
递归减少C,增加A的长度
1 | type RepeatString< |
33. implement TupleToString<T>
题目
Implement TupleToString<T> to return a new type by concatenating all the string to a new string type.
1 | type A = TupleToString<['a']> // 'a' |
答案
拼接字符串,直到剩下的数组长度为0
1 | type TupleToString<T extends string[]> = |
34. implement Repeat<T, C>
题目
Implement Repeat<T, C> to return a tuple by repeating.
1 | type A = Repeat<number, 3> // [number, number, number] |
答案
negative case of C could be ignored.
拼接字符串,直到字符串数组长度为等于设置的C
1 | type Repeat<T, C extends number, A extends T[] = []> = |
35. implement Filter<T, A>
题目
Implement Filter<T, A> to return a new tuple type by filtering all the types from T that are assignable to A.
1 | type A = Filter<[1,'BFE', 2, true, 'dev'], number> // [1, 2] |
答案
把每项展开,如果符合条件加入结果数组中
1 | type Filter<T extends any[], A> = T extends [infer L, ...infer R] |
36. implement LargerThan<A, B>
题目
Implement LargerThan<A, B> to compare two positive integers.
1 | type A = LargerThan<0, 1> // false |
答案
把每项展开,如果符合条件加入结果数组中,利用数组长度进行判断
1 | type LargerThan<A extends number, B extends number, S extends number[] = []> = |
如果考虑小数和负数是怎么写的?这样写!
1 | type NSymbol = 0 | 1 |
37. implement SmallerThan<A, B>
题目
Implement SmallerThan<A, B> to compare two positive integers.
1 | type A = SmallerThan<0, 1> // true |
答案
把每项展开,如果符合条件加入结果数组中,利用数组长度进行判断
1 | type SmallerThan<A extends number, B extends number, S extends number[] = []> = |
38. implement Add<A, B>
题目
Implement Add<A, B> to get the sum of two positive integers.
1 | type A = Add<1, 2> // 3 |
答案
用两个数组分别记录2个数对应的长度,利用数组长度相加的结果
1 | type Add<A extends number, B extends number, C extends any[] = [], D extends any[] = []> = |
39. implement ToNumber<T>
题目
Implement ToNumber<T> to get an integer number type from integer string.
1 | type A = ToNumber<'1'> // 1 |
答案
we can just consider smaller numbers
用数组分别记长度,然后利用模板引擎转化为字符串
1 | type ToNumber< |
40. implement UnionToIntersection<T>
题目
Implement UnionToIntersection<T> to get an Intersection type from Union type.
1 | type A = UnionToIntersection<{a: string} | {b: string} | {c: string}> |
答案
The article : TypeScript: Union to intersection https://zhuanlan.zhihu.com/p/526988538
After reading about the contra-variance thing, I finally understand why casting T to function works. Great explanation, huge kudos to the author 🎉
利用函数的输入参数将T中的|转化为&
1 | type UnionToIntersection<T> = |
41. implement FindIndex<T, E>
题目
Just like Array.prototype.findIndex(), please implement FindIndex<T, E>.
1 | type A = [any, never, 1, '2', true] |
答案
首先判断2个元素是否相同,再通过数组第一个元素是否相同递归查找有无相同元素,通过一个辅助数组长度来计算个数
1 | type Equal<A, B> = |
42. implement Equal<A, B>
题目
Implement Equal<A, B> to check if two types are identical.
1 | Equal<any, any> // true |
答案
there might not be a 100% perfect solution, so are the test cases from us.
let’s all try with our best effort.
其实上一题就需要这种判断方法了
1 | type Equal<A, B> = |
43. implement Trim<T>
题目
Please implement Trim<T> just like String.prototype.trim().
1 | type A = Trim<' BFE.dev'> // 'BFE' |
答案
用递归的方法先去除左边的空格,再去除右边的空格
1 | //extends 如果T包含的类型 是 U包含的类型的 '子集',那么取结果X,否则取结果Y。 |
44. implement ReplaceAll<S, F, T>
题目
Just like String.prototype.replaceAll(),
please implement ReplaceAll<S, F, T>.
1 | type A = ReplaceAll<'aba', 'b', ''> // 'aa' |
答案
1、前、中、后分别取一下infer。 2、 判断F不为空
1 | type ReplaceAll< |
45. implement Slice<A, S, E>
题目
Just like what Array.prototype.slice() does, please implement Slice<A, S, E>.
1 | type A = Slice<[1,2,3,4], 0, 2> // [1, 2] |
Let’s assume end index
Ewon’t be negative
答案
采用了每次比较大小的方式,到20时候就爆zhan了, 想到了优化方式:先转化成数组,然后根据数组infer出来
https://typescript.easy-pp.com/modules.html
1 | type LessThan<A extends number, B extends number, S extends any[] = []> = |
46. implement Subtract<A, B>
题目
Similar to 38. implement Add, please implement Subtract<A, B>.
- only need to consider positive integers
- B is guaranteed to be smaller or equal to A
1 | type A = Subtract<1, 1> // 0 |
答案
1 | type LessThan<A extends number, B extends number, S extends any[] = []> = |
47. implement Multiply<A, B>
题目
Implement Multiply<A, B>
1 | type A = Multiply<1, 0> // 0 |
Only need to consider non-negative integers.
答案
1 | type RepeatAny <B extends number , C extends any[] = []> = |
48. implement Divide<A, B>
题目
Implement Divide<A, B>
1 | type A = Divide<1, 0> // never |
Only need to consider non-negative integers.
答案
通过减法实现除法
1 | type Tuple<T extends number, U extends any[] = []> = |
49. asserts never
题目
In switch, it is easy for us to miss out some cases.
1 | type Value = 'a' | 'b' | 'c'; |
We missed out case 'c' in above code and compiler doesn’t compain.
Plase create function assertsNever() to check for exhaustiveness.
1 | type Value = 'a' | 'b' | 'c'; |
Now TypeScript would complaint the missing case 'c'.
答案
断言函数输入
1 | declare const assertsNever: (arg: never) => void; |
或者
1 | function assertsNever (arg: never) { |
50. implement Sort<T>
题目
You are able to compare two non-negative integers in LargerThan and SmallerThan, then you should be able to implement Sort<T> in ascending order.
1 | type A = Sort<[100, 9, 20, 0, 0 55]> |
答案
选择排序
1 | type LessThan<A, B, T extends any[] = []> = |
或者
插入排序
判断数字是否在 number[] 中,剔除 number 中的该数字
1 | type MyExclude<A extends any[], B extends number, N extends any[] = [], F extends boolean = false> = ( |
51. implement Capitalize<T>
题目
Implement MyCapitalize<T> to capitalize strings.
1 | type A = MyCapitalize<'bfe'> // 'Bfe' |
There is built-in
Capitalize<T>in TypeScript, maybe you can try not to use it.
答案
利用Uppercase将首字母转化为大写
1 | type MyCapitalize<T extends string> = |
52. implement Split<S, D>
题目
Just like String.prototype.split(), please implement Split<S, D>.
1 | type A = Split<'BFE.dev', '.'> // ['BFE', 'dev'] |
答案
利用模板字符串分割
1 | type Split<S extends string, D extends string, A extends string[] = []> = |
53. Implement SnakeCase<S>
题目
Implement SnakeCase<S> to turn string in camel case to snake case.
1 | type A = SnakeCase<'BigFrontEnd'> // big_front_end |
答案
将大写字母转成小写,且除首个之外前面加上_
1 | type isUpperCase<T extends string> = |
54. Implement CamelCase<S>
题目
Implement CamelCase<S> to turn string in snake case to camel case.
1 | type A = CamelCase<'big_front_end'> // BigFrontEnd |
答案
模板引擎替换首字母和第一个字母
1 | type CamelCase<S extends string> = |
55. implement StringToNumber<S>
题目
Implement StringToNumber<S> to convert string to number. You can assume strings are all valid non-negative integers.
1 | type A = StringToNumber<'12'> // 12 |
答案
数组长度将字符串转数组转数字
1 | type StringToNumber<S extends string, T extends any[] = []> = |
56. implement Abs<N>
题目
Implement Abs<N> to get the absolute value of a number. You can assume the number are integers.
答案
负数转字符串再计算长度
1 | type StringToNumber<S extends string, T extends any[] = []> = |
57. implement ObjectPaths<O>
题目
Implement ObjectPaths<O> to return all valid paths to properties.
1 | type Obj = { |
答案
有难度,直接copy大佬的答案
1 | type Key = string | number | symbol; |
58. implement Diff<A, B>
题目
Implement DiffKeys<A, B> to return the keys either in A or B, but not in both.
1 | type A = DiffKeys<{a: 1, b: 2}, {b: 1, c: 2}> // 'a' | 'c' |
答案
借助Exclude
1 | type DiffKeys< |