大厂面试TS(上)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值