跳至主要內容
BFE-TS TypeScript类型体操练习 41- 50

BFE-TS TypeScript类型体操练习 41- 50

题目来自TypeScript题目 | BFE.dev - 前端刷题,准备前端面试拿到心仪的Offer,总共60题,带你完爆类型体操!

常用工具类型 41-44

  1. 实现 LengthOfString<T>

    实现LengthOfString<T>用以返回字符串长度。

    type A = LengthOfString<'BFE.dev'> // 7
    type B = LengthOfString<''> // 0
    

    答案:

    1. 转为元组后直接访问泛型的.length属性

      type StringToTuple<T extends string> = T extends `${infer L}${infer R}` ? [L, ...StringToTuple<R>] : [];
      type LengthOfString<T extends string> = StringToTuple<T>['length'];
      
    2. 辅助数组统计长度

      type LengthOfString<
        T extends string,
        U extends 0[] = []
      > = T extends `${infer A}${infer B}`
        ? LengthOfString<B, [0, ...U]>
        : U["length"];
      
  2. 实现 LengthOfTuple<T>

    实现LengthOfTuple<T>返回tuple type的长度。

    type A = LengthOfTuple<['B', 'F', 'E']> // 3
    type B = LengthOfTuple<[]> // 0
    

    答案:

    直接访问泛型的.length属性

    type LengthOfTuple<T extends any[]> = T["length"]
    
  3. 实现 StringToTuple<T>

    实现StringToTuple<T>将字符串拆散为tuple,类似String.prototype.split('')效果

    type A = StringToTuple<'BFE.dev'> // ['B', 'F', 'E', '.', 'd', 'e','v']
    type B = StringToTuple<''> // []
    

    答案:

    type StringToTuple<T extends string> = T extends `${infer A}${infer B}` ? [A, ...StringToTuple<B>] : []
    
  4. 实现 LastItem<T>

    FirstItem<T>类似,请实现LastItem<T>用以返回tuple的最后一个type

    type A = LastItem<[string, number, boolean]> // boolean
    type B = LastItem<['B', 'F', 'E']> // 'E'
    type C = LastItem<[]> // never
    

    答案:

    type LastItem<T extends any[]> = T extends [...infer Firsts, infer Last] ? Last : never
    

    相类似的

    type LastItem<T extends any[]> = T extends [...any[], infer M] ? M : never;
    

Yihui大约 3 分钟TypeScript
BFE-TS TypeScript类型体操练习 51- 60

BFE-TS TypeScript类型体操练习 51- 60

题目来自TypeScript题目 | BFE.dev - 前端刷题,准备前端面试拿到心仪的Offer,总共60题,带你完爆类型体操!

有挑战性的题目 51-60

  1. 实现CamelCase<S>

    将下划线连接转为驼峰(snake case to camel case)

    type A = CamelCase<'big_front_end'> // BigFrontEnd
    

    答案:

    type CamelCase<S extends string> = 
      S extends `${infer L}_${infer R}`
        ? CamelCase<`${Capitalize<L>}${Capitalize<R>}`>
        : Capitalize<S>
    

    Capitalize<S> 为4.1新增关键字TypeScript 4.1 新特性之字符串模板类型 - boygdm - 博客园

  2. 实现SnakeCase<S>

    经典的大驼峰转下划线连接(camel case to snake case),注意首字母转小写

    type A = SnakeCase<'BigFrontEnd'> // big_front_end
    

    答案:

    即分为大小写判定和添加前缀,然后组合成新的字符串,O(n)解法:

    type isUpperCase<T extends string> = T extends '' ? false : (Uppercase<T> extends T ? true : false);
    
    type Prefix<T extends string, Skip extends boolean> = Skip extends false ? (isUpperCase<T> extends true ? `_${Lowercase<T>}` : T) : Lowercase<T>;
    
    type SnakeCase<T extends string, Skip extends boolean = true> = T extends `${infer A}${infer B}` ? (
      `${Prefix<A, Skip>}${SnakeCase<B, false>}`
    ) : T
    
  3. 实现Split<S, D>

    即实现类String.prototype.split()的功能

    type A = Split<'BFE.dev', '.'> // ['BFE', 'dev']
    type B = Split<'bfe.dev', 'e'> // ['bf', '.d', 'v']
    type C = Split<'bfe.bfe.bfe', 'bfe'> // ['', '.', '.', '']
    

    答案:

    type Split<
      S extends string, 
      D extends string,
      ResultType extends string[] = [],
    > = S extends `${infer F}${D}${infer Rest}`
      ? Split<Rest, D, [...ResultType, F]>
      : [...ResultType, S];
    

    这与StringToTuple<T>有点相似,参考:

    type StringToTuple<T extends string> = T extends `${infer A}${infer B}` ? [A, ...StringToTuple<B>] : []
    
  4. 实现Capitalize<T>

    实现字符串首字母大写,实际上TS已经内置了该工具类型,请尝试自己实现

    type A = MyCapitalize<'bfe'> // 'Bfe'
    

    答案:

    type MyCapitalize<T extends string> = T extends `${infer P}${infer U}` ? `${Uppercase<P>}${U}` : T;
    
  5. 实现Sort<T>

    升序排序。如果能够比较 LargerThan<A,B>SmallerThan<A,B> 中的两个非负整数,那么你应该能够实现升序排序。

    type A = Sort<[100, 9, 20, 0, 0 55]>
    // [0, 0, 9, 55, 100]
    

    找不同,即A,B中只存在一边的keys

    type A = DiffKeys<{a: 1, b: 2}, {b: 1, c: 2}> // 'a' | 'c'
    

    答案:

    type DiffKeys<
      A extends Record<string, any>,
      B extends Record<string, any>
    > = Exclude<keyof A, keyof B> | Exclude<keyof B, keyof A>
    
  6. asserts never

    switch,我们很容易犯一些错误,比如,

    type Value = 'a' | 'b' | 'c';
    declare let value: Value
    
    switch (value) {
      case 'a':
        break;
      case 'b':
        break;
      default:
        break;
    }
    

    我们遗忘了case c,但是编辑器没有给予提示

    所以,请实现函数assertsNever()去检查以保证没有遗漏的case

    type Value = 'a' | 'b' | 'c';
    declare let value: Value
    
    switch (value) {
      case 'a':
        break;
      case 'b':
        break;
      default:
        assertsNever(value)
        break;
    }
    

    此时TypeScript会警告你缺失了case c

    答案:

    可以通过的答案,但可能不太合适?

    function assertsNever (arg:never) {
      throw new TypeError(`Missing case ${arg}`)
    };
    
  7. 实现Divide<A, B>

    即计算A/B,保留整数结果,注意对0的处理

    type A = Divide<1, 0> // never
    type B = Divide<4, 2> // 2
    type C = Divide<10, 3> // 3
    

    答案:

    可以理解为模拟计算,例如10/3,逐个减去3,计算可以减掉多少个3,直到剩下1,无法在被3减去,输出之前所减去的3的个数

    type Tuple<T extends number, U extends any[] = []> =
      U['length'] extends T ? U : Tuple<T, [...U, any]>
    
    type Subtract<
      A extends number,
      B extends number
      > = Tuple<A> extends [...Tuple<B>, ...infer R] ? R['length'] : never
    
    type SmallerThan<
      A extends number,
      B extends number,
      S extends number[] = []
    > = S['length'] extends B
      ? false
      : S['length'] extends A
      ? true
      : SmallerThan<A, B, [A, ...S]>
    type Divide<A extends number, B extends number, S extends number[] = []> = 
    B extends 0 ? never : SmallerThan<A,B> extends true ? S['length'] : Divide<Subtract<A, B>, B, [...S, any]>;
    
  8. 实现Multiply<A, B>

    即A*B的计算,其中A,B均为非负整数

    type A = Multiply<1, 0> // 0
    type B = Multiply<4, 6> // 24
    

    答案:

    type Tuple<T extends number, U extends any[] = []> =
      U['length'] extends T ? U : Tuple<T, [...U, any]>
      
    type MinusOne<T extends number> =
      Tuple<T> extends [any, ...infer R] ? R['length'] : 0
      
    type MultiplyHelper<T extends any[], U extends number, I extends any[] = []> =
      U extends 0 ? I['length'] : MultiplyHelper<T, MinusOne<U>, [...T, ...I]>
    
    type Multiply<A extends number, B extends number> = MultiplyHelper<Tuple<A>, B>
    
  9. 实现Subtract<A, B>

    只需要考虑正整数,并且 B 保证小于或等于 A

    type A = Subtract<1, 1> // 0
    type B = Subtract<10, 3> // 7
    type C = Subtract<3, 10> // never
    

    答案:

    type _P<A, B, S = 0, T extends unknown[] = [], C extends unknown[] = []> = S extends 1 ? (
      // 1代表start已经相等了,在寻找end
      T['length'] extends B ? [...C, 1]['length'] : _P<A, B, S, [...T, 1], [...C, 1]>
    ) : (
        T['length'] extends B ? never :
        // 先和2位匹配到为never
        (
          _P<A, B, T['length'] extends A ? 1 : 0, [...T, 1], C>
          // 和第一位匹配到
        )
      )
    
    type Subtract<A extends number, B extends number> = A extends B ? 0 : _P<B, A>
    
  10. 实现Slice<A, S, E>

    即实现类似Array.prototype.slice()

    type A = Slice<[1,2,3,4], 0, 2> // [1, 2]
    type B = Slice<[1,2,3,4], 2> // [3, 4]
    type C = Slice<[number, boolean, bigint], 2, 5> // [bigint]
    type D = Slice<[string, boolean], 0, 1> // [string]
    type E = Slice<[number, boolean, bigint], 5, 6> // []
    

    其中E不为负数

    答案:

    // 截取L之后的元素,包括L
    type RemoveStart<
      A extends any[],
      L extends number,
      ResultType extends any[] = []
    > = ResultType['length'] extends L ? A : (
      A extends [infer First, ...infer Rest] ? (
        RemoveStart<Rest, L, [...ResultType, First]>
      ) : []
    );
    
    // 截取L之前的元素,不包括L
    type RemoveEnd<
      A extends any[],
      L extends number,
      ResultType extends any[] = []
    > = ResultType['length'] extends L ? ResultType : (
      A extends [infer First, ...infer Rest] ? (
        RemoveEnd<Rest, L, [...ResultType, First]>
      ) : [...ResultType, ...A]
    );
    
    type Slice<
      A extends any[], 
      S extends number = 0, 
      E extends number = A['length'],
    > = RemoveStart<RemoveEnd<A, E>, S>;
    

Yihui大约 4 分钟TypeScript
BFE-TS TypeScript类型体操练习 Easy 31-40

BFE-TS TypeScript类型体操练习 Easy 31-40

题目来自TypeScript题目 | BFE.dev - 前端刷题,准备前端面试拿到心仪的Offer,总共60题,带你完爆类型体操!

常用工具类型

  1. 实现 Repeat<T, C>

    返回一个进行重复复制操作的元组

    type A = Repeat<number, 3> // [number, number, number]
    type B = Repeat<string, 2> // [string, string]
    type C = Repeat<1, 1> // [1, 1]
    type D = Repeat<0, 0> // []
    

    答案:

    思路与RepeatString<T, C>差不多

    type Repeat<T, C extends number, R extends any[] = []> = R['length'] extends C ? R : Repeat<T, C ,[...R, T]>
    
  2. 实现 TupleToString<T>

    通过将所有字符串连接成为新的字符串类型

    type A = TupleToString<['a']> // 'a'
    type B = TupleToString<['B', 'F', 'E']> // 'BFE'
    type C = TupleToString<[]> // ''
    

    答案:

    type TupleToString<T extends unknown[]> = T extends [infer F, ...infer R] ? F extends string ? `${F}${TupleToString<R>}` : never : "";
    
  3. 实现 RepeatString<T, C>

    类似于String.prototype.repeat(),即对字符串的重复复制,注意C为0的情况

    type A = RepeatString<'a', 3> // 'aaa'
    type B = RepeatString<'a', 0> // ''
    

    答案:

    即递归直至A(作为最终字符串的长度达到C的数值)

    type RepeatString<T extends string, C extends number, A extends string[] = []> = A['length'] extends C
        ? ''
        : `${T}${RepeatString<T, C, [T, ...A]>}`;
    
  4. 实现 Push<T, I>

    类似数组Push操作,入栈

    type A = Push<[1,2,3], 4> // [1,2,3,4]
    type B = Push<[1], 2> // [1, 2]
    type C = Push<[], string> // [string]
    

    答案:

    type Push<T extends any[], I> = [...T, I]
    
  5. 实现 IsAny<T>

    type A = IsAny<string> // false
    type B = IsAny<any> // true
    type C = IsAny<unknown> // false
    type D = IsAny<never> // false
    

    答案:

    按照any作为顶级类型理解,就是说any是任何类型的父类,any 类型可以赋值给除了 never 之外的任意其他类型,但反过来不能把 unknown 赋值给除了 any 之外的任何其他类型,但其他类型都可以赋值给 unknown

    type IsAny<T> = [unknown] extends [T] ? ([T] extends [string | number | symbol | boolean] ? true : false) : false
    

    补:Any与Unknown的区别

    unknow类型只是一个Top Type,而any既是一个Top Type也是一个Bottom Type。正因为如此编辑器才不会对any进行类型检查。

    总的来说:使用unknow还能保持类型安全,使用any就默认放弃类型检查。所以any是一个危险的类型,它可以自由转换为其他类型,其他类型也可以自由转换为any类型,编译器不对该类型的实例进行类型检查。所以开发者有义务确保不会发生错误解释类型的情况。

    一行的解决方法:

    type IsAny<T> = 0 extends 1&T ? true:false;
    
  6. 实现 Shift<T>

    类似数组Shift操作,去除元组第一个元素

    type A = Shift<[1,2,3]> // [2,3]
    type B = Shift<[1]> // []
    type C = Shift<[]> // []
    

    答案:

    type Shift<T extends any[]> = T extends [infer P, ...infer M] ? M : []
    
  7. 实现 IsEmptyType<T>

    检查T是否为空对象,注意any视为非空

    type A = IsEmptyType<string> // false
    type B = IsEmptyType<{a: 3}> // false
    type C = IsEmptyType<{}> // true
    type D = IsEmptyType<any> // false
    type E = IsEmptyType<object> // false
    type F = IsEmptyType<Object> // false
    

    答案:

    type IsEmptyType<T> = T extends Record<string,string> ? [keyof T] extends [never] ? true: false: false
    

    抑或是分别检测是否为简单非空对象和Any类型

    type simpleObject = { [key: string]: string }
    type IsAny<T> = false extends (true & T) ? true : false; 
    type IsEmptyType<T> = IsAny<T> extends true ? false : {} extends T ? T extends simpleObject ? true : false :false 
    
  8. 实现 Flat<T>

    即实现元组类型扁平化

    type A = Flat<[1,2,3]> // [1,2,3]
    type B = Flat<[1,[2,3], [4,[5,[6]]]]> // [1,2,3,4,5,6]
    type C = Flat<[]> // []
    

    答案:

    type Flat<T extends any[]> = T extends [infer K, ...infer R] ? (K extends any[] ? [...Flat<K>,...Flat<R>] : [K,...Flat<R>]) : T
    
  9. 实现 ReverseTuple<T>

    即实现对元组类型的翻转

    type A = ReverseTuple<[string, number, boolean]> // [boolean, number, string]
    type B = ReverseTuple<[1,2,3]> // [3,2,1]
    type C = ReverseTuple<[]> // []
    

    答案:

    type ReverseTuple<T extends any[]> = 
      T extends [...infer L, infer R] ? [R, ...ReverseTuple<L>]: []
    
  10. 实现 UnwrapPromise<T>

    即展开Promise,返回resolved后的类型

    type A = UnwrapPromise<Promise<string>> // string
    type B = UnwrapPromise<Promise<null>> // null
    type C = UnwrapPromise<null> // Error
    

    答案:

    type UnwrapPromise<T extends Promise<any>> = T extends Promise<infer P> ? P :never
    

Yihui大约 3 分钟TypeScript
BFE-TS TypeScript类型体操练习 Easy 21-30

BFE-TS TypeScript类型体操练习 Easy 21-30

常用工具类型

  1. 实现 ReplaceAll<S, F, T>

    正如String.prototype.replaceAll(),请实现ReplaceAll<S, F, T>

    type A = ReplaceAll<'aba', 'b', ''> // 'aa'
    type B = ReplaceAll<'ababbab', 'b', ''> // 'aaa'
    

    答案:

    1、前、中、后分别取一下infer。

    2、 判断F不为空

    type ReplaceAll<
      S extends string,
      F extends string,
      T extends string
      > = F extends '' ? S : (S extends `${F}${infer R}` ? `${T}${ReplaceAll<R, F, T>}` :
        (S extends `${infer A}${F}${infer B}` ? `${A}${T}${ReplaceAll<B, F, T>}` :
          S extends `${infer A}${F}` ? `${ReplaceAll<A, F, T>}${T}` : S
        ));
    
  2. 实现 Trim<T> 正如String.prototype.trim(),请实现Trim<T>

    type A = Trim<'    BFE.dev'> // 'BFE'
    type B = Trim<' BFE. dev  '> // 'BFE. dev'
    type C = Trim<'  BFE .   dev  '> // 'BFE .   dev'
    

    答案:

    type Trim<T extends string> = T extends ` ${infer R}` 
      ? Trim<R> 
      : T extends `${infer L} `
        ? Trim<L>
        : T
    
  3. 实现 Equal<A, B> 检测俩类型是完全相同的

    Equal<any, any> // true
    Equal<any, 1> // false
    Equal<never, never> // true
    Equal<'BFE', 'BFE'> // true
    Equal<'BFE', string> // false
    Equal<1 | 2, 2 | 1> // true
    Equal<{a : number}, {a: number}> // true
    

    答案:

    type Equal<T, K> = [T] extends [K] ? [K] extends [T] ? (keyof T extends keyof K ? keyof K extends keyof T ? true : false : false) : false : false;
    
    // or
    
    type Equals<X, Y> =
      (<T>() => T extends X ? 1 : 2) extends
      (<T>() => T extends Y ? 1 : 2) ? true : false;
    
  4. 实现 FindIndex<T, E> 正如Array.prototype.findIndex(), 请实现FindIndex<T, E>

    type A = [any, never, 1, '2', true]
    type B = FindIndex<A, 1> // 2
    type C = FindIndex<A, 3> // never
    

    答案:

    type Equals<X, Y> =
      (<T>() => T extends X ? 1 : 2) extends
      (<T>() => T extends Y ? 1 : 2) ? true : false;
    
    type FindIndex<T extends any[], E> =
      T extends [...infer Rest, infer EE]
      ? Equals<EE, E> extends true
        ? FindIndex<Rest, E> extends never
          ? Rest["length"]
          : FindIndex<Rest, E>
        : FindIndex<Rest, E>
      : never;
    
  5. 实现 UnionToIntersection<T> 请实现UnionToIntersection<T>用以从Union(或)得到Intersection(与/交)。

    type A = UnionToIntersection<{a: string} | {b: string} | {c: string}> 
    // {a: string} & {b: string} & {c: string}
    

    答案:

    type UnionToIntersection<U> = 
      (
        U extends any 
          ? (x: U) => void 
          : never
      ) extends ((x: infer I) => void) 
          ? I 
          : never
    

    关于这是如何工作的可以参见typescript - Transform union type to intersection type - Stack Overflow

  6. 实现 ToNumber<T> 请实现ToNumber<T>用来转换字符串为整数。

    type A = ToNumber<'1'> // 1
    type B = ToNumber<'40'> // 40
    type C = ToNumber<'0'> // 0
    

    答案:

    type ToNumber<T extends string, U extends number[] = []> =
      `${U['length']}` extends T
        ? U['length']
        : ToNumber<T, [...U, 1]>
    
  7. 实现 Add<A, B> 实现Add<A, B>计算正整数之和。

    type A = Add<1, 2> // 3
    type B = Add<0, 0> // 0
    

    答案:

    type Tuple<T extends number, U extends any[] = []> = U['length'] extends T ? U : Tuple<T, [...U, any]>
    
    type Add<A extends number, B extends number> = [...Tuple<A>, ...Tuple<B>]['length']
    
  8. 实现 SmallerThan<A, B>

    type A = SmallerThan<0, 1> // true
    type B = SmallerThan<1, 0> // false
    type C = SmallerThan<10, 9> // false
    

    答案:

    type SmallerThan<
      A extends number,
      B extends number,
      S extends number[] = []
    > = S['length'] extends B
      ? false
      : S['length'] extends A
      ? true
      : SmallerThan<A, B, [A, ...S]>
    
  9. 实现 LargerThan<A, B>

    type A = LargerThan<0, 1> // false
    type B = LargerThan<1, 0> // true
    type C = LargerThan<10, 9> // true
    

    答案:

    type LargerThan<A extends number, B extends number, S extends any[] = []> =
      S['length'] extends A
      ? false
      : S['length'] extends B
      ? true
      : LargerThan<A, B, [...S, any]>
    

    继续推进数组,直到它到达其中一个数字,到达的第一个数字就是较小的

  10. 实现 Filter<T, A> 实现Filter<T, A>,返回T中能够assign给A的type所组成的新tuple。

    type A = Filter<[1,'BFE', 2, true, 'dev'], number> // [1, 2]
    type B = Filter<[1,'BFE', 2, true, 'dev'], string> // ['BFE', 'dev']
    type C = Filter<[1,'BFE', 2, any, 'dev'], string> // ['BFE', any, 'dev']
    

    答案:

    type Filter<T extends any[], A, R extends A[] = []> = 
      T extends [infer F, ...infer O] 
        ? [F] extends [A]
          ? Filter<O, A, [...R, F]>
          : Filter<O, A, R>
        : R
    

Yihui大约 3 分钟TypeScript
BFE-TS TypeScript类型体操练习 Easy 11-20

BFE-TS TypeScript类型体操练习 Easy 11-20

题目来自TypeScript题目 | BFE.dev - 前端刷题,准备前端面试拿到心仪的Offer,总共60题,带你完爆类型体操!

Utility types 内置工具类型实现 11-15

  1. 实现 ConstructorParameters<T>

    Parameters处理的是function type。 与之类似,ConstructorParameters<T>针对的是class,返回constructor function T的其参数type组成的tuple type。

    class Foo {
      constructor (a: string, b: number, c: boolean) {}
    }
    
    type C = MyConstructorParameters<typeof Foo> 
    // [a: string, b: number, c: boolean]
    

    答案:

    type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
    
  2. 实现ReturnType<T>

    Parameters<T>处理的是参数, ReturnType<T>,正如起名所述,处理的是function type T的返回值type

    type Foo = () => {a: string}
    
    type A = MyReturnType<Foo> // {a: string}
    

    通过 infer 推断函数返回值

    答案:

    type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
    
  3. 实现InstanceType<T>

    对于constructor function type T,InstanceType<T> 返回其instance type。

    class Foo {}
    type A = MyInstanceType<typeof Foo> // Foo
    type B = MyInstanceType<() => string> // Error
    

    通过 infer 推断 new 后返回的类型

    答案:

    type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
    
  4. 实现ThisParameterType<T>

    对于function type T,ThisParameterType<T>返回this type。 如果没有指定,则使用unknown

    function Foo(this: {a: string}) {}
    function Bar() {}
    
    type A = MyThisParameterType<typeof Foo> // {a: string}
    type B = MyThisParameterType<typeof Bar> // unknown
    

    通过 infer 推断函数的 this 类型

    答案:

    type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown;
    
  5. 实现OmitThisParameter<T>

    Function.prototype.bind()返回一个this已经bind过后的function。 对于这种情况,可以用OmitThisParameter<T>来增加type信息。

    function foo(this: {a: string}) {}
    foo() // Error
    
    const bar = foo.bind({a: 'BFE.dev'})
    bar() // OK
    
    
    type Foo = (this: {a: string}) => string
    type Bar = MyOmitThisParameter<Foo> // () => string
    

    因推断时自动忽略函数的 this 类型,因此直接通过推断后的参数类型和返回值类型包装成个函数返回即可

    答案:

    type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;
    

Yihui大约 3 分钟TypeScript
BFE-TS TypeScript类型体操练习 Easy 1-10

BFE-TS TypeScript类型体操练习 Easy 1-10

题目来自TypeScript题目 | BFE.dev - 前端刷题,准备前端面试拿到心仪的Offer,总共60题,带你完爆类型体操!

Utility types 内置工具类型实现

  1. 实现Partial

    Partial<T>返回一个包含所有T的子集的type。

    type Foo = {
      a: string
      b: number
      c: boolean
    }// below are all validconst a: MyPartial<Foo> = {}const b: MyPartial<Foo> = {
      a: 'BFE.dev'
    }const c: MyPartial<Foo> = {
      b: 123
    }const d: MyPartial<Foo> = {
      b: 123,
      c: true
    }const e: MyPartial<Foo> = {
      a: 'BFE.dev',
      b: 123,
      c: true
    }
    

    答案:

    type Partial<T> = {
        [P in keyof T]?: T[P];
    };
    
  2. 实现Required

    Partial<T>正好相反, Required<T>会将所有的属性设为required。

    // all properties are optional
    type Foo = {
      a?: string
      b?: number
      c?: boolean
    }
    ​
    ​
    const a: MyRequired<Foo> = {}
    // Errorconst b: MyRequired<Foo> = {
      a: 'BFE.dev'
    }
    // Errorconst c: MyRequired<Foo> = {
      b: 123
    }
    // Errorconst d: MyRequired<Foo> = {
      b: 123,
      c: true
    }
    // Errorconst e: MyRequired<Foo> = {
      a: 'BFE.dev',
      b: 123,
      c: true
    }
    // valid
    

    答案:

    type Required<T> = {
        [P in keyof T]-?: T[P];
    };
    
  3. 实现Readonly

    答案:

    type Readonly<T> = {
        readonly [P in keyof T]: T[P];
    };
    
  4. 实现Record

    Record<K, V>返回一个key是K值是V的object type。

    type Key = 'a' | 'b' | 'c'const a: Record<Key, string> = {
      a: 'BFE.dev',
      b: 'BFE.dev',
      c: 'BFE.dev'
    }
    a.a = 'bigfrontend.dev' // OK
    a.b = 123 // Error
    a.d = 'BFE.dev' // Errortype Foo = MyRecord<{a: string}, string> // Error
    

    答案:

    type Record<K extends keyof any, T> = {
        [P in K]: T;
    };
    
  5. 实现Pick

    Pick<T, K>,正如其名所示,将从T中抽选出K中含有的属性然后返回一个新的type。

    type Foo = {
      a: string
      b: number
      c: boolean
    }type A = MyPick<Foo, 'a' | 'b'> // {a: string, b: number}
    type B = MyPick<Foo, 'c'> // {c: boolean}
    type C = MyPick<Foo, 'd'> // Error
    

    答案:

    type Pick<T, K extends keyof T> = {
        [P in K]: T[P];
    };
    
  6. 实现Omit

    Omit<T, K>返回一个从T的属性中剔除掉K过后的type。

    type Foo = {
      a: string
      b: number
      c: boolean
    }type A = MyOmit<Foo, 'a' | 'b'> // {c: boolean}
    type B = MyOmit<Foo, 'c'> // {a: string, b: number}
    type C = MyOmit<Foo, 'c' | 'd'> // {a: string, b: number}
    

    答案:

    type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
    
  7. 实现Exclude

    Exclude<T, K>返回一个从T中去掉能代入K的成员后的type。

    type Foo = 'a' | 'b' | 'c'type A = MyExclude<Foo, 'a'> // 'b' | 'c'
    type B = MyExclude<Foo, 'c'> // 'a' | 'b
    type C = MyExclude<Foo, 'c' | 'd'>  // 'a' | 'b'
    type D = MyExclude<Foo, 'a' | 'b' | 'c'>  // never
    

    答案:

    type Exclude<T, U> = T extends U ? never : T;
    
  8. 实现Extract

    和Exclude正好相反, Extract<T, U>返回T中可以代入到U的成员所组成的type。

    type Foo = 'a' | 'b' | 'c'type A = MyExtract<Foo, 'a'> // 'a'
    type B = MyExtract<Foo, 'a' | 'b'> // 'a' | 'b'
    type C = MyExtract<Foo, 'b' | 'c' | 'd' | 'e'>  // 'b' | 'c'
    type D = MyExtract<Foo, never>  // never
    

    答案:

    type Extract<T, U> = T extends U ? T : never;
    
  9. 实现NonNullable

    剔除 null | undefined 类型,表明非空

    答案:

    type NonNullable<T> = T extends null | undefined ? never : T;
    
  10. 实现Parameters

    对于function type T, Parameters<T> 返回一个由其参数type组成的tuple type。

    type Foo = (a: string, b: number, c: boolean) => stringtype A = MyParameters<Foo> // [a:string, b: number, c:boolean]
    type B = A[0] // string
    type C = MyParameters<{a: string}> // Error
    

    答案:

    type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
    

Yihui大约 3 分钟TypeScript
TS 装饰器使用一览

TS 装饰器使用一览

来自官网:

装饰器是一种包装代码的简单方法,它也是一种设计模式,能够扩展包装代码的功能而不修改它。

尽管装饰器在 TypeScript 和 Python 等语言中被广泛使用,但是 JavaScript 装饰器的支持仍处于第 2 阶段提案中。但是,我们可以借助 Babel 和 TypeScript 编译器使用 JavaScript 装饰器。

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上

是一种在不改变原类和使用继承的情况下,动态地扩展对象功能


Yihui大约 3 分钟TypeScript
TypeScript 面试专题

TypeScript 面试专题

interface 与 type 异同点

这可能是最经典的一道 TS 面试题了,因此这里我们放在第一个知识点来讲解。

及格线

不论如何,以下这些概念是你需要基本了解的,否则很容易被怀疑是否真的深入使用过 TypeScript 。

  • 在对象扩展情况下,interface 使用 extends 关键字,而 type 使用交叉类型(&)。
  • 同名的 interface 会自动合并,并且在合并时会要求兼容原接口的结构。
  • interface 与 type 都可以描述对象类型、函数类型、Class 类型,但 interface 无法像 type 那样表达元组、一组联合类型等等。
  • interface 无法使用映射类型等类型工具,也就意味着在类型编程场景中我们还是应该使用 type 。

Yihui大约 32 分钟面试题前端TypeScript
TypeScript 笔记

TypeScript 笔记

⭐PS: 本内容不能作为入门学习使用,仅用于补充完善我个人对TS的知识点

TypeScript是拥有类型的JavaScript超集,它可以编译成普通、干净、完整的JavaScript代码

理解

  • 我们可以将TypeScript理解成加强版的JavaScript。
  • JavaScript所拥有的特性,TypeScript全部都是支持的,并且它紧随ECMAScript的标准,所以ES6、ES7、ES8等新语法标准,它都是 支持的;
  • 并且在语言层面上,不仅仅增加了类型约束,而且包括一些语法的扩展,比如枚举类型(Enum)、元组类型(Tuple)等;
  • 并且TypeScript最终会被编译成JavaScript代码,所以你并不需要担心它的兼容性问题,在编译时也不需要借助于Babel这样的工具;

Yihui大约 14 分钟TypeScript
函数泛型

函数泛型

箭头函数泛型

直接以内嵌式书写的箭头函数泛型,以复用函数

const foo = <T,>(x: T): T => x;

const foo = <T extends {}>(x: T): T => x;

const foo = <T extends Record<string, unknown>>(x: T): T => x;

const foo: <T>(x: T) => T = x => x;

const identity = <T,>(arg: T): T => {
    console.log(arg);
    return arg;
};

const renderAuthorize = <T>(Authorized: T): ((currentAuthority: CurrentAuthorityType) => T) => (
    currentAuthority: CurrentAuthorityType,
  ): T => {
     return
 };

Yihui大约 2 分钟TypeScript
2