笔记8--ts

130 阅读5分钟

一、ts概念

1. 什么是ts

  • 原理

    ts是js的一个超集,在js原有的语法上,添加了可选静态类型和基于类的面向对象编程

  • 项目

    • ts:面向解决大型复杂项目,多人协同架构及代码维护复杂的场景
    • js:脚本化语言,面向相对简单的单页面场景
  • 自主检测

    • ts:编译期间,主动发现并纠正提示错误 ⇒ 执行前检测
    • js:运行时报错
  • 类型检测

    • ts:弱类型,编译时支持动态和静态类型检测
    • js:弱类型,无静态类型选项
  • 运行流程

    • ts:依赖编译,打包实现并转义成浏览器可运行的代码
    • js:可以直接被浏览器运行
  • 复杂特性

    • ts:模块化、泛型、接口

2. 安装运行

npm install -g typescript
tsc -v

tsc ./test.ts

面试点

  • 所有的类型检测和纠错阶段

    编译时

二、ts基础类型与写法

  • boolean
  • string
  • number
  • array
  • null
  • undefined
// js
let editable = true;
let text = 'hello world';
let num = 2;
let u = undefined;
let n = null;
let arr = ['basic', 'execute'];

// ts
let editable: boolean = true;
let text: string = 'hello world';
let num: number = 2;
let u: undefined = undefined;
let n: null = null;
let arr: string[] = ['basic', 'execute'];
let arr: Array<string> = ['basic', 'execute'];
  • tuple 元组
let tupleType: [string, boolean];
tupleType = ['text', true];
  • enum 枚举
// 数字类型枚举 -- 默认从零开始,依次递增
enum Score {
	BAD,
	NG,
	GOOD,
	PERFECT
}

let score: Score = Score.BAD;

// 字符串类型枚举
enum Score {
	BAD: 'bad',
	NG: 'ng',
	GOOD: 'good',
	PERFECT: 'perfect'
}

// 值
enum Score {
	BAD, // 0
	NG,
	GOOD,
	PERFECT
}

// 反向映射
enum Score {
	BAD, // 0
	NG,
	GOOD,
	PERFECT
}

let scoreName = Score[0]; // BAD
let scoreValue = Score['BAD']; // 0

// 异构状态
enum Enum{
	A, // 0
	B, // 1
	C = "C",
	D = "D",
	E = 6,
	F // 7
}
// 面试题:指出每种具体值
// 1. 第一个未明确赋值的项目为0,所有未赋值项目依次排列,直到数字被打断
// 2. 从数字打断处,以数字作为起始值,依次排列
// 3. 有明确赋值的项目,保留赋值

// 引出 => js本质实现(手写异构枚举)
let Enum;
(function(Enum){
    // 正向
    Enum["A"] = 0;
    Enum["B"] = 1;
    Enum["C"] = "C";
    Enum["D"] = "D";
    Enum["E"] = 6;
    Enum["F"] = 7;
    // 逆向
    Enum["0"] = "A";
    Enum["1"] = "B";
    Enum["6"] = "E";
    Enum["7"] = "F";
})
  • any:绕过所有类型检测 ⇒ 类型检测、编译筛查全部失效。级别最高

    let anyValue: any = 123;
    anyValue = 'anyValue';
    anyValue = false;
    let Value1: boolean = anyValue;
    
  • unknown:绕过赋值检查 ⇒ 禁止更改传递

    let unknownValue: unknown;
    
    unknownValue = true;
    unknownValue = 123;
    
    let value1: unknown = unknownValue; // 合法
    let value2: any = unknownValue; // 合法
    
    let value3: boolean = unknownValue; // 不合法
    
  • void:与any相反,用于声明返回值 ⇒ 会结束,但没有返回值

    function voidFunction(): void{
    	console.log('void function');
    }
    
  • never:永不返回,永远error

    function error(msg: string): never{
    	throw new Error(msg);
    }
    
    function longlongloop(): never{
    	while(true){
    		...
    	}
    }
    

三、对象

  • object:非原始类型

    tsjs Object分成两个接口定义

    interface ObjectConstructor{
    	create(o: object | null): any;
    }
    
    const proto = {};
    
    Object.create(Proto); // 合法
    Object.create(null); // 合法
    Object.create(undefined); // 不合法
    
  • Object

    Object.prototype 上的属性

    interface Object{
    	constructor: FUnction;
    	toString(): string;
    	valueOf(): object;
    	hasOwnProperty(v: PropertyKey): boolean;
    	isPrototypeOf(v: object): boole
    }
    

    定义了Object类属性

    interface ObjectConstructor{
    	new(value: any): object;
    	readonly prototype: Object;
    }
    
  • {}:定义空属性

    优点:防止新属性添加紊乱

    cons tobj = {};
    obj.class = 'text'; // Error
    
    const obj = {};
    obj.toString(); // Ok
    

四、接口(interface

  • 对行为的抽象,具体行为实现由类实现

    // 描述对象的内容,不实现具体逻辑
    interface Class{
    	name: string;
    	time: number
    }
    
    let text: Class{
    	name: "typeScript",
    	time: 2022
    }
    
  • 只读

    interface Clas{
    	readonly name: string;
    	time: number;
    }
    

面试题

  • 和js引用的不同 ⇒ const

    let arr: number[] = [1, 2, 3, 4];
    let ro: ReadonlyArray<number> = arr;
    
    ro[0] = 2; // 赋值 Error
    ro.push(5); // 增加 Error
    ro.length = 100; // 修改长度 Error
    arr = ro; // 覆盖 Error
    
  • 任意可添加属性

    interface Class{
    	readonly name: string;
    	time: number;
    	[propName: string]: any // 可任意添加属性
    }
    
    const c1 = {name: "js"};
    const c2 = {name: "browser", time: 2022, level: 1};
    const c3 = {name: "typescript", time: 2023, isTrail: true};
    

五、交叉类型(&)

interface A { x: D };
interface B { x: E };
interface C { x: F };

interface D { d: boolean };
interface E { e: string };
interface F { f: number };

type ABC = A & B & C;
let abc: ABC = {
	d: false,
	e: "text",
	f: 5
}

面试题

  • 合并冲突问题

    interface A {
        c: string;
        d: string;
     }
    
     interface B {
        c: number;
        e: string;
     }
    
     type AB = A & B;
    
     let ab: AB = {
    	d: 'class',
    	e: 'text'
     }
     // 合并关系是且 => c: never
    

六、断言(类型声明、转换)(对编译器的告知交流)

  • 编译时作用

    // 尖括号形式声明 -- 阶段性类型
    let anyValue: any = 'value';
     let anyValue: number = (<string>anyValue).length;
    
     // AS 声明
     let anyValue: any = 'value';
     let anyLength: number = (anyValue as string).length;
    
     // 非空判断 -- 只确定不是空
     type ClassTime = () => number;
     const start = (classTime: ClassTIme | undefined) =>{
        let num = classTime!(); // 具体类型待定,但确定非空
     }
    

    面试题

    const tsClass: number | undefined  = undefined;
    const test: number = tsClass!;
    console.log(test); // 编译时通过
    
    'use strict'
    const tsClass = undefined;
    const test = tsClass;
    console.log(test); // undefined
    

    存在的意义是?

    肯定断言 — 肯定化保证赋值

    let score!: number;
    startClass();
    console.log(2 * score);
    
    function startClass(){
    	score = 5;
    }
    // let score!: number -- 告知编译器,运行时,会被赋值的
    

七、类型守卫 — 保障在语法规定的范围内,额外的确认

  • 多态:多种状态(多种类型)

    // in -- 定义属性场景下的内容确认
    interface Teacher{
        name: string;
        courses: string[];
    }
    
    interface Student{
        name: string;
        startDate: Date;
    }
    
    type Class = Teacher | Student;
    
    function startCourse(cls: Class){
        if('courses' in cls){
            console.log('i m teacher');
        }
        if('startTime' in cls){
            console.log('i m student');
        }
    }
    
    // typeof / instanceof -- 类型分类场景下的身份确认
    
    // typeof
    function class(name: string, score: string | number){
        if (typeof score === 'number') {
            console.log('teacher');
        }
        if (typeof score === 'string') {
            console.log('student');
        }
    }
    
    // instanceof
    interface Teacher{
        name: string;
        courses: string[];
    }
    
    interface Student{
        name: string;
        startDate: Date;
    }
    
    type Class = Teacher | Student;
    
    const getName = (cls: Class) => {
        if (cls instanceof Teacher) {
            return cls.courses;
        }
        if (cls instanceof Student) {
            return cls.name;
        }
    }
    
    // 自定义类型
    const isTeacher = function (cls: Teacher | Student): cls is Teacher {
        return 'courses' in cls;
    }
    
    const getName = (cls: Teacher | Student) => {
        if (isTeacher(cls)) {
            return cls.courses;
        }
    }
    

八、ts进阶

1. 函数重载

class Class {
    start(name: number, score: number): number;
    start(name: string, score: string): string;
    start(name: Combinable, score: Combinable) {
        if (typeof name === 'string' || typeof score === 'string') {
            return 'student' + name + score;
        }
        return 'teacher' + name + score;
    }
}

2. 泛型 — 重用

  • 让模块可以支持多种类型的数据 — 类型和值一样可以赋值传递

    function startClass<T, U>(name: T, score: U): T {
        return name + score;
    }
    function startClass<T, U>(name: T, score: U): string {
        return `${name}${score}`
    }
    function startClass<T, U>(name: T, score: U): T {
        return (name + String(score)) as any as T;
    }
    
    startClass<Number, String>('yy', 5);
    

3. 装饰器 — decorator

function test(target: Function): void{
    target.prototype.startClass = function(): void{
        // startClass
    }
}

@test
class Class{
    //......
}

// 属性装饰器
function nameWrapper(target: any, key: string) {
    // ......
    Object.defineProperty(target, key, {
        // getter & setter
    })
}

class Class {
    @nameWrapper
    public name: string;
}