美文网首页
大厂面试TS(上)

大厂面试TS(上)

作者: Famous | 来源:发表于2022-07-11 20:52 被阅读0次

    一、TS面试基础知识

    1、什么是TS?

    • 概念:
      ts 是 js 的超集,即在原有的js语法基础上,添加强类型并切换为基于类的面向对象语言
    • 特点

    面向项目:
    TS - 面向解决大型的复杂项目、架构、代码维护复杂场景
    JS - 脚本化语言,用于面向简单页面场景

    自主检测:
    TS - 编译时,主动发现并纠正错误
    JS - 运行时,执行报错

    类型检测:
    TS - 强类型语言,支持动态和静态的类型检测
    JS - 弱类型语言,无静态类型选项

    运行流程:
    TS - 依赖编译,依靠编译打包实现在浏览器端的运行
    JS - 可直接在浏览器端运行

    复杂特性:
    TS - 模块化、接口、泛型

    2、安装运行

      npm install -g typescript
      tsc -v
      tsc xxx.ts
    

    举栗: 问: 在字符串后面加上:string,代码运行时,这个string还存在吗? 有什么办法在运行时改变这个string吗?
    答案: 不存在了,也没必要去修改这个string,它是在编译时为变量指定了一个类型。

    3、TS 基础类型和语法

    • 类型: boolean 、string 、number 、arrary、 null 、undefined
    // es
    let a = false;
    // ts
    let a:boolean = false;
    // 统一方式 & <> 方式
    let classArr: string[] = ['1', '2'];
    let classArr: Array<string> = ['1', '2']
    
    • 那如果数组中的各个元素类型不一样的话呢?
      tuple - 元祖
    let tupleType:[string, boolean] = ['1', true]
    
    • 特定的几个值呢 ====> 也就是枚举?
       // 数字型枚举 - 默认从0开始,一次递增
      enum Store {
          BAD, // 不写默认0分
          GOOD, // 不写默认1分
          NICE=10, // 写默认10分
      }
      let score: Score = Score.BAD;
      // 字符串枚举 - 默认从0开始,一次递增
      enum Store {
          BAD = 'BAD', 
          GOOD = 'GOOD',
          NICE = 'NICE', 
      }
      // 反向映射
       enum Store {
          BAD, // 不写默认0分
          GOOD, // 不写默认1分
          NICE=10, // 写默认10分
      }
      let scoreName = Score[0] // 结果为'BAD'
      let scoreValue = Score['BAD'] // 结果0
      // 异构
      enum Enum{
        A,     // 0
        B,     // 1
        C = 'C',
        D = 'D',
        E = 8,
        F       // 9
      }
      // 面试题: 异构类型每一项的枚举值 => 进而问如何手写一个异构枚举??
      let Enum;
     (function (Enum) {
       // 正向
       Enum['A'] = 0;
       Enum['B'] = 1;
       Enum['C'] = 'C';
       Enum['D'] = 'D';
       Enum['E'] =8;
       Enum['F'] = 9;
    
       // 逆向
       Enum[0] = 'A';
       Enum[1] = 'B';
       Enum[8] = 'E';
       Enum[9] = 'F';
    
      })(Enum || Enum = {})
    
    • 那我想绕过所有的类型检查呢 ==> any 类型检查和编译筛查取消
       let anyValue:any = '1';
       anyValue = false;
       let value1:boolean = anyValue // OK 使用前无需判断any类型
    
    • 还有一个种方式是 ==> unknown 绕过赋值检查,禁止更改传递
       let unknownValue: unknown = '1';
       unknownValue = 123;
       unknownValue = false;
       let aa:unknown = unknownValue // OK 
       let bb:any = unknownValue // OK 
       let cc:boolean = unknownValue // OK
       let cc:string = unknownValue // Error  使用之前要先判断类型是否符合
    

    上述两种方式any 和unknown 有何区别??
    1、任何类型都可以是any类型,ts 允许any类型的值进行任何操作,对它一路绿灯,等于免检标签。可以访问任意属性和方法。
    2、任何类型都可以是unknown类型,一旦打上标签,会被重点检查,只要类型检查通过了才能进行操作。

    说人话?? 举栗如下::

    // 从后台拿到数据,不知道类型,按照不同类型走不同的逻辑处理
    let a:unknown = JSON.stringify({result: []})
    if (typeof a === 'string'){
        let b = JSON.parse(a)
    } 
    // 或者 使用断言
    let score:unknown = 99.8
    let result = Math.round(score as number); // 这要求运行时的score必须是number才能过检查
    let result1 = Math.round(<number>score); // 这是另一种写法 
    
    • 如何声明返回为空,没有任何类型? (告诉编辑器函数没有返回值)
    // 比如没有返回值的函数
    function voidFunction():void{
       console.log('void')
    }
    
    • 永不能执行完 or 永远error (永远不会有值)
    // 比如专门用来报错的函数
    function errMsg(msg:string):never{
       throw new Error(msg)
    }
    // 或者永不会结束的函数
    function infiniteLoop:never{
         while(true) {  }
    }
    

    4、接口 - interface

    • 区分开object / Object / {} - 三个不同的对象
    // object - 非原始类型
    interface ObjectConstructor{
        create(o:object | null):any
    }
    const proto = {}
    Object.create(proto);
    Object.create(null);
    Object.create(undefined); // Error
    // Object 
    // Obect.prototype 上的属性保留了
    interface Object {
        constructor: Function;
        toString():string;
        toLocaleString():string;
        valueOf():Object;
    }
    // 定义了Object 类属性
    interface ObjectConstructor{
        new(value:any):Object;
        readonly property:Object;
    }
    // {} - 定义真正的空属性对象
    const obj = {}
    obj.prop = 'props'; // Error
    
    obj.toString(); // OK
    
    • 对行为模块的抽象,具体的行为是由类来实现
    // 描述对象内容
    interface Class1 {
      // 只读
      readonly name:string;
      age: number;
    }
    let Wang = {
         name: 'Famous',
         age: 11
    }
    // 面试题 readonly  与 js 的引用操作类型不同 < = > const
    let arr:number[] = [1,2,3,4]
    let ro: ReadonlyArray<number> = arr;
    ro[0] = 12 // ok吗? 
    ro.push(5); // ok吗?
    ro.length = 10; // ok吗?
    arr = ro; // ok吗
    // 答案是全部报错
    
    • 那我想要允许添加一些可能的属性呢?有些属性可能要不断增加进去
    // 任意可添加属性
    interface Class1 {
      readonly name:string;
      [propName:string]:any; 
    }
    let c1 = {name: 'JS'}
    let c2 = {name: 'TS', level: 1} // level 就是后续新增的属性
    

    5、交叉类型 - &

    // 合并
    interface A {
        inner: D;
    }
    interface B {
        inner: E;
    }
    interface C {
        inner: F;
    }
    interface D {
        d: boolean;
    }
    interface E {
        e: string;
    }
    interface F {
        f: number;
    }
    
    type ABC = A & B & C;
    let abc:ABC = {
        inner:{
           d:false;
           e: 'className',
           f: 5     
       }
    }
    // 合并冲突
    interface A {
        c:string;
        d:string;
    }
    interface B {
        c:number;
        d:string;
    }
    type AB = A & B
    let ab: AB  // 此时 c 是string 也是number, 变成never 编译时会直接报错
    

    6、断言 - 类型声明和转换(开发者和编译器做了一个告知交流)

    • 编译时作用
    let anyValue:any = 'hi Lu'
    // 尖括号形式
    let anyLength:number = (<string>anyValue).length;
    // as
    let anyLength:number = (anyValue as string).length;
    // 非空判断 - 只确定不是空
    type A = () => number;
    const start = (param: A | undefined){
      // 业务逻辑
      // if (额外判断逻辑){
          let time = param!();  // 具体类型待定,但是非空确认
       }
    }
    // 面试题
    const tsClass:number | undefined = undefined;
    const aa:number = tsClass!
    console.log(tsClass) // 做好了非空判断吗?
    // 上述回转义成为
    const tsClass = undefined;
    const aa = tsClass // undefined
    
    // 结论 尽量不要在赋值的时候去断言
    
    // 肯定断言 - 肯定化保证赋值
    let score:number;
    startClass();
    console.log(score) // 使用前赋值
    function startClass(){
      score = 5;
    }
    // 应该这样写 let score!:number; 
    // 上述代码一般要在写score时就赋值,而不是等后面再赋值,但是写了断言 ,提前打好招呼,示意等下会有赋值,编辑器就不会报错了。
    

    7、类型守卫 - 语法规范范围内,额外的确认

    • 多态 - 多钟状态(多钟类型)
    // in - 定义属性场景下内容的确认(类不适合合并,走导流)
    interface Teacher {
      name: string;
      courses:string[];
     }
    interface Student {
      name: string;
      startTime:Date;
     }
    type ClassA =  Teacher | Student
    function startCourse(cls:Class){
        if ('courses' in cls){
            console.log('Courses:' + cls.courses)
        }
        if ('startTime' in cls){
             console.log('startTime:' + cls. startTime)
       }
    }
    // typeof / instanceof - 类型分类场景下的身份确认
    function class(name:string, score:string | number){
         if (typeof score === 'number'){
             return 'teacher:' + name + ':' + score;
         } else if (typeof score === 'string'){
            return 'student:' + name + ':' + score;
         }
    }
    // instanceof
    const getName = (cls:Class){
      if (cls instanceof Teacher){
          return cls.courses
      } else if (){
         return cls.startTime
      }
    }
    // 自定义类型 起个别的名字,更好认一点
     const isTeacher = function(cls: Teacher | Student):cls is Teacher {
       return 'courses' in cls
    }
    const getName = (cls:Teacher | Student)=>{
        if (isTeacher(cls)){
             return cls.courses
        }
    }
    

    8、TS 进阶

    • 函数重载 - 复用
       class Course {
         start(name:number, score:number):number;
         start(name: string, score:string):string;
         start(name: string, score: number): string;
         start(name: number, score: number): string;
         start(name: Conbinable, score: Conbinable){
              if (typeof name == 'string' || typeof score == 'string') {
                   return 'student:' + name + ':' + score;
              }
         }
       }
       const course = new Course();
       course.start('小红', 5) 
    
    • 泛型 - 复用 (简单一句话: 类型可控)
    • 让模块可以支持多种类型数据 - 让类型声明和值一样,可以被赋值和传递
        function startClass <T, U>(name: T, score: U):T{
            return name + score;
        }
        console.log(startClass<Number, String>('小红', 5))
       // T、U、K - 键值、V - 值 、E - 节点、元素
    
    • 装饰器 - decorator 用处很大,通用性的操作
        // 1、类装饰器
        function decorator1(target:Function):void{
            target.prototype.startClass = function():void{
               // 通用功能
           }
         } 
       // 2、属性装饰器
        function propsWrapper(target:any, key:string){
           // 属性的统一操作
          Object.defineProperty(target, key,{
          })
        }
        // 3、方法装饰器 - target: Object, propertyKey:string, descriptor: TypePropertyDescript
        @decorator1
        class Course {
            constructor(){
              // 业务逻辑 
            }
            @propsWrapper
            public name:string;
             
            @methodDec
         }
    

    相关文章

      网友评论

          本文标题:大厂面试TS(上)

          本文链接:https://www.haomeiwen.com/subject/eqdnbrtx.html