首页 > 其他分享 >一道字节的 TS 体操面试真题

一道字节的 TS 体操面试真题

时间:2024-01-15 11:31:34浏览次数:27  
标签:字节 真题 MM TS YY Num extends type infer

前天,小册群友问了我一个 TS 体操问题,说是面字节时遇到的。

一道字节的 TS 体操面试真题_字面量

今天又催了一下:

一道字节的 TS 体操面试真题_字符串_02

面试题是这样的:

一道字节的 TS 体操面试真题_TypeScript_03

让实现这个 FormatDate 的类型,用来限制字符串只能是指定的日期格式。

看起来好像没多大难度,就是提取出 YY、MM、DD 和分隔符,然后构造对应的字符串类型就好了。

但上手试了一下,还真没那么简单。

首先,我们用模式匹配的方式,也就是 extends + infer 来提取出 YY、MM、DD 这三部分:

type Seperator = '-' | '.' | '/';

type FormatDate<Pattern extends string> =
  Pattern extends `${infer Aaa}${Seperator}${infer Bbb}${Seperator}${infer Ccc}`
    ? [Aaa,Bbb,Ccc]
    : never;

一道字节的 TS 体操面试真题_TypeScript_04

一道字节的 TS 体操面试真题_JavaScript_05

同样,也可以提取出分隔符部分:

type FormatDate<Pattern extends string> =
  Pattern extends `${infer Aaa}${Seperator}${infer Bbb}${Seperator}${infer Ccc}`
    ? Pattern extends `${Aaa}${infer Sep}${Bbb}${infer _}${Ccc}`
      ? [Aaa, Bbb, Ccc, Sep]
      : never
    : never;

一道字节的 TS 体操面试真题_字面量_06

一道字节的 TS 体操面试真题_字面量_07

然后根据 YY、MM、DD 分别构造 4 位和 2 位的字符串,最后组合起来不就行了?

但问题就在这里。

组合字符串字面量类型是这样写:

type Num = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

type YY = `${Num}${Num}${Num}${Num}`;

type MM = `${Num}${Num}`;

type DD = `${Num}${Num}`;

type GenStr<Type extends string> =
  Type extends 'YY'
    ? YY
    : Type extends 'MM'
      ? MM
      : DD;

type res3 = `${GenStr<'YY'>}-${GenStr<'MM'>}-${GenStr<'DD'>}`;

就是根据 YY、MM 还是 DD 生成不同的字符串字面量,然后组合到一块。

这时候会提示你 union 数量太多:

一道字节的 TS 体操面试真题_字符串_08

因为组合起来的情况太多了。

这时候需要减少 union 数量才行。

所以我们可以改成这样:

type Num = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

type Num2 = Num | 0

type YY = `19${Num2}${Num2}` | `20${Num2}${Num2}`;

type MM = `0${Num}` | `1${0 | 1 | 2}`;

type DD = `${0}${Num}` | `${1 | 2}${Num2}` | `3${0 | 1}`;

type GenStr<Type extends string> =
  Type extends 'YY'
    ? YY
    : Type extends 'MM'
      ? MM
      : DD;

type res3 = `${GenStr<'YY'>}-${GenStr<'MM'>}-${GenStr<'DD'>}`;

也就是年份只能是 19 和 20 开头,月份只能是 1-12 的数字,日期是 01-31 的数字。

这样,组合就少了很多。

再试下:

一道字节的 TS 体操面试真题_前端_09

现在就能正常计算出类型了。

然后用之前提取出的 Aaa、Bbb、Ccc 和 Sep 来生成字符串字面量类型:

一道字节的 TS 体操面试真题_JavaScript_10

这样,就完成了需求:

一道字节的 TS 体操面试真题_字面量_11

一道字节的 TS 体操面试真题_TypeScript_12

一道字节的 TS 体操面试真题_字面量_13

回过头来看一下,这个类型难么?

思路并不难,就是通过模式匹配(extends + infer)提取出各部分,然后构造对应的字符串字面量类型,组合起来就好了。

它难在如果直接组合,union 数量会过多,从而报错。

所以需要根据年月日的特点,对生成的字符串字面量类型做更精准的控制。

这样,就能生成满足需求的日期字符串类型。

全部代码如下,大家可以试试:

type Seperator = '-' | '.' | '/';

type Num = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

type Num2 = Num | 0

type YY = `19${Num2}${Num2}` | `20${Num2}${Num2}`;

type MM = `0${Num}` | `1${0 | 1 | 2}`;

type DD = `${0}${Num}` | `${1 | 2}${Num2}` | `3${0 | 1}`;

type GenStr<Type extends string> =
  Type extends 'YY'
    ? YY
    : Type extends 'MM'
      ? MM
      : DD;

type FormatDate<Pattern extends string> =
  Pattern extends `${infer Aaa}${Seperator}${infer Bbb}${Seperator}${infer Ccc}`
    ? Pattern extends `${Aaa}${infer Sep}${Bbb}${infer _}${Ccc}`
      ? `${GenStr<Aaa>}${Sep}${GenStr<Bbb>}${Sep}${GenStr<Ccc>}`
      : never
    : never;

const a: FormatDate<'YY-MM-DD'> = '2023-01-02';

const b: FormatDate<'DD/MM/YY'> = '01/02/2024';

const c: FormatDate<'DD/MM/YY'> = '2024-01-02';

playground 地址

更多内容可以看我的小册:TypeScript 类型体操通关秘籍

总结

今天我们做了一道字节的 ts 体操真题。

核心思路就是模式匹配(extends + infer)提取出各部分内容,然后构造日期字符串。

答出这个,应该就有大部分的分了。

但是如果直接构造,会因为 union 数量太多导致失败。

这时候要根据日期的特点想办法减少 union 的数量,直到可以顺利生成。

再答出这个,这道面试题就稳了。

这道题整体来说还是比较难的,既考察了模式匹配+ 构造的 ts 类型编程基础,又考察了对 union 太多的情况的处理,算是一道比较高阶的面试题。

标签:字节,真题,MM,TS,YY,Num,extends,type,infer
From: https://blog.51cto.com/u_15506823/9251355

相关文章

  • 下一代APP Store——GPT应用商店GPTs初体验
    uploading-image-126879.png近期,OpenAI宣布GPT应用商店正式上线,目前拥有plus的用户已经可以体验了。OpenAI将GPT应用商店命名为GPTs,这也是之前发布会就宣传的内容,终于上线了。简单的说,GPT应用商店类似于手机上的应用商店,在这里用户可以自己做一个应用发布,也可以使用别人的应用。......
  • 20款最好的免费 Bootstrap 后台管理和前端模板
    20款最好的免费Bootstrap后台管理和前端模板 AdminBootstrapTemplatesFreeDownload 1.SBAdmin2Preview | Details&Download2.AdminLitePreview | Details&Download3.DirectorResponsiveAdminTemplateFreePreview | Details&Download4......
  • 关于echarts+vue频繁刷新的造成的内存增长问题
    前言关于解决echarts+ws多次数据刷新渲染,内存增长溢出的尝试。记录一下,便于下次使用有参考方法关闭echarts动画tooltip的动画设置为false。(echarts动画会缓存,通过快照可以看出)tooltip:{axisPointer:{animation:false,//很重要!},......
  • 初中英语优秀范文100篇-058The Importance of Doing Sports-做运动的重要性
    PDF格式公众号回复关键字:SHCZFW058记忆树1Nowadays,moreandmorepeopleprefertostayathomewatchingTVandsurfingtheInternet,whichleadstofatnessandevenseriousillness.翻译如今,越来越多的人更喜欢待在家里看电视和上网,这导致了肥胖,甚至严重的疾病......
  • DIANN-MSstats groupComparison Issue: undefined columns selected
    1.Whaterrormessagedidyouencounter?Errorin`[.data.frame`(as.data.frame(comparisons),,cols):undefinedcolumnsselected 2.Howdidyousolvetheerror?install.packages("lme4",type="source") 3.Whatarethepos......
  • ArkTS父子组件双向绑定案例
     /***父子组件双向互绑定*///自定义按钮的信息类型classButtonState{value:stringwidth:numberconstructor(value:string,width:number){this.value=valuethis.width=width}}@ComponentstructMyChildGreenButton{//拥有绿色......
  • ArkTS Prop组件使用案例
      /***Prop组件使用案例*/@ComponentstructMyChild{@Propage:number//状态变量privateincrease:number=1build(){Column(){if(this.age>=18){Text(`子组件中的age已经成年了:${this.age}`).height(80)......
  • 使用TVertScrollbox自定义列表数据
    界面布局设置如下创建一个过程添加新项目procedureTForm1.AddItem(name:string;age:Integer);varlayout:TLayout;begin//设置姓名标签的文本Label3.Text:=name;//设置年龄标签的文本Label4.Text:=IntToStr(age);//克隆Layout1,并将克隆得到......
  • 【小记】BITMAP To BMP 调用 GetDIBits 引发栈内存损坏问题
    BITMAPbitmap;if(!GetObject(hBitmap,sizeof(bitmap),&bitmap)){//外部传入hBitmapreturnfalse;}//创建位图信息头BITMAPINFObitInfo;BITMAPINFOHEADER&bi=bitInfo.bmiHeader;bi.biWidth=bitmap.bmWidth;bi.biHeight=bitmap.bmHeight;bi.biPlane......
  • 一线大厂面试真题--对双亲委派的理解
    首先,简单说一下类的加载机制(如图),就是我们自己写的java源文件到最终运行,必须要经过编译和类加载两个阶段。编译的过程就是把.java文件编译成.class文件。类加载的过程,就是把class文件装载到JVM内存中,装载完成以后就会得到一个Class对象,我们就可以使用new关键字来实例化这个对象。(......