TypeScript详解

文章目录

      • [一.TS 基础概念](#一.TS 基础概念)
        • 1.什么是TS
        • 2.TS基础类型与写法
        • [* boolean string number array null undefined](#* boolean string number array null undefined)
        • [* tuple - 元组](#* tuple - 元组)
        • [* enum - 枚举](#* enum - 枚举)
        • [* any unknown void](#* any unknown void)
        • [* object | Object | {} - 对象](#* object | Object | {} - 对象)
      • [二. 接口 - interface](#二. 接口 - interface)
      • 三.交叉类型
      • [四.断言 - 类型声明,转换](#四.断言 - 类型声明,转换)
      • [五.类型守卫 -Type Guards](#五.类型守卫 -Type Guards)
      • 六.TS进阶
        • [1.泛型(Generics) - 重用](#1.泛型(Generics) - 重用)
        • [2.装饰器 - decorator](#2.装饰器 - decorator)

一.TS 基础概念

1.什么是TS
  • 对比原理

  • ts是 js 的一个超集,在原有基础上添加了

  • 可选静态类型

  • 基于类的面向对象编程

  1. 编写项目 - 更利于架构维护
  2. 自主检测 - 编译期间检测
  3. 类型检测 - 支持了动态和静态类型检测;ts不是强类型语言=》本质上还是存在类型转换
  4. 运行流程 - 依赖编译
  5. 复杂特性 - 模块化,泛型,接口
2.TS基础类型与写法
* boolean string number array null undefined
typescript 复制代码
// es
let isEnable = true;
let class = "ts";
let classNum = 2;
let classArr = ["basic","execute"];

// ts
let isEnable:boolean = true;
let class:string = "ts";
let classNum:number = 2;
// 数组的两种写法
let classArr:string[]= ["basic","execute"];
let classArr:Array<string> = ["basic","execute"];
* tuple - 元组

数组的搭配比较多样,用来声明数组中有多种类型时使用

typescript 复制代码
let tupleType:[string,boolean] 
  tupleType =["ts",true]
* enum - 枚举
typescript 复制代码
// 数字枚举- 默认从零开始,依次递增
enum Score {
  BAD,
  NG,
  GOOD,
  PERFECT
}
let score:Score = Score.BAD;

// 字符串类型
enum Score {
  BAD="BAD",
  NG="NG",
  GOOD="GOOD",
  PERFECT="PERFECT"
}

// 反响映射
enum Score {
  BAD,
  NG,
  GOOD,
  PERFECT
}
let scoreName = Score[0]; // "BAD",因为默认依次递增
let scoreValue = Score["BAD"];// 0

// 异构 (数字和字符串都有)
// 字符串设置什么就是什么
// 数字类型依据上一个加一
enum Score {
  A, //0
  B, //1
  C='C',
  D="D",
  E=6,
  F // 7
}
* any unknown void
typescript 复制代码
// 输入
//any - 绕过所有检查 => 类型检测和编译筛查全部失效
let anyValue:any =123;

anyValue ="anyValue";

// unknown - 绕过赋值检查=> 禁止更改传递
// 传递
let unkonwnValue:unknown;

 unknownValue="unknownValue";

let value1:unknown =unknownValue;//ok
let value2:any=unknownValue;//ok
let value3:boolean = unknownValue;/nok

// 返回
// void - 声明函数返回值 不返回任何值
function voidFunction():void{
  console.lg("no return")
}

// nerver - 永不返回
function error(msg:string):never{
  throw new Error(msg)
}
function longlongloop():never{
  while(true)
}
* object | Object | {} - 对象
typescript 复制代码
// object - 非原始类型
interface ObjectConstrutor {
  create(o:object | null):any;
}

const proto = {};
Object.create(proto);//ok

// Object  - 原型属性
// Object.prototype 上的属性
interface Object {
  constructor:Function;
  toString():string;
  valueOf():Object
}

// {} - 空对象 - 没有成员的对象
const a = {} as A; // 通过断言来设置
a.class = "es"; 
a.name=30; // {} 表示空对象,赋值会抛出异常

二. 接口 - interface

在TypeScript中,接口是一种定义对象形状的方式,它描述了对象应该有哪些属性和方法,但并不直接提供这些属性和方法的实现。接口主要用于确保类或其他结构(如对象字面量)符合特定的契约

  1. 定义属性:接口可以定义对象的属性类型,但不包括属性值。
  2. 定义方法:接口可以定义对象的方法,但不包括方法的实现
  3. 只读属性:使用 readonly 关键字可以定义只读属性,即这些属性只能做对象被创建时被赋值,之后不能被修改
  4. 继承接口:一个接口可以继承另一个或者多个接口,从而继承它们的属性和方法
javascript 复制代码
interface Class {
  name:string;
  time:number
}
let course:Class = {
  name:"ts",
  time:2
}

//只读
interface Class {
  readonly name:string;
  time:number
}
// 任意
interface Class {
  name:string;
  time:number
  [propName:string]:any
}
// 面试题:ts 和 js的引用的不同
let arr:number[] = [1,2,3,4];
let ro:ReadonlyArray<number> = arr;

ro[0] = 12; //Error - 只读状态不可赋值
ro.push(5); //Error - 增加
ro.length = 100; //Error - 长度改写

arr = ro;//Error - 覆盖

//定义方法
interface Greeter {
  greet(message: string): void;
}

class PersonGreeter implements Greeter {
  greet(message: string) {
    console.log(`Hello, ${message}`);
  }
}

//继承
interface Named {
  name:string;
}
interface Person extends Named{
  age:number
}

const person:Person = {
  name:"张三",
  age:18
}

三.交叉类型

在TypeScript中,交叉类型是一种组合多个类型到一个单一类型的方式。通过交叉类型,你可以创建一个新的类型,这个类型具有所有被组合类型的特性。当一个对象具有多个类型的属性时通过&符号来定义的

  • 交叉类型和运算符里面的 与( && ) 是一样的,既要 ... 又要 ... 还要
  • 可以把两个对象合并到一个对象
typescript 复制代码
// 合并
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 ={
  x:{
    d:false,
    e:"class",
    f:5
  }
}

// 合并冲突
interface A {
  c:string;
  d:string
}
interface B {
  c:number;
  d:string
}
type AB = A & B;
// 合并关系是并且 => c:never

四.断言 - 类型声明,转换

在TypeScript中,断言是一种告诉编译器我们对某个表达式类型的明确预期的方式。通过使用断言,我们可以为编译器提供额外的信息,以确保在编译时能够正确地处理类型。断言不仅用于声明变量的类型,还可以用于在类型之间进行显式转换,从而确保代码的类型安全性。

typescript 复制代码
// 尖括号
let anyValue:any = 'hi ts';
// 当anyValue是 string 时去取length
let anyLength:number = (<string>anyValue).length; //阶段性声明;

// as 声明
let anyLength:number = (anyValue as string).length; //阶段性声明;

// 非空判断 - 非空断言操作符 !
// 非空断言操作符,用于告知编译器我确定这个值是非空的,不需要再进行类型检查
type ClassTime = () => number;

const start = (classTime:ClassTime | undefined)=>{
  let num = classTime!(); //确认一定不会为空
}

五.类型守卫 -Type Guards

在TypeScript中,类型守卫是一种特殊的表达式,它允许你执行运行时检查以缩小一个值的类型范围。类型守卫可以用于确保一个值是某种特定的类型,或者在多种类型之间进行区分。

typeof | instanceof 类型守卫

在TypeScript中,typeof 和 instanceof 运算符被特殊对待,并被认为是类型守卫。当它们用于类型检查时,TypeScript会缩小变量的类型范围。

typescript 复制代码
interface Teacher {
  name:string;
  courses:string[];
}
interface Student{
  name:string;
  startTime:Date;
}

type Class = Teacher | Student

function startCourse(cls:Class){
    if('courses' in cls){
      // teacher
    }
    if("startTime" in cls){
      // student
    }
}

function startCourse(cls:Class){
    if(cls intanceof Teacher){
      // teacher
    }
    if(cls intanceof Student){
      // student
    }
}

function startCourse(name:string,score:string | number){
    if(typeof score === "number"){
      // teacher
    }
    if(typeof score === "string"){
      // student
    }
}

六.TS进阶

1.泛型(Generics) - 重用

在 TypeScript 中,泛型是一种允许你为组件(如类、接口和函数)创建可复用的类型的方式,而无需在每次使用组件时都明确指定类型。泛型提供了一种创建可重用组件的方式,这些组件可以工作于多种数据类型。

  1. 泛型函数:泛型函数是指在调用指定类型参数的函数。在函数后面使用(其中 T 是类型变量)
  2. 泛型类:泛型类是在类定义中使用类型变量的类
  3. 泛型接口:中接口定义中引入类型变量
  4. 泛型约束:定义泛型时,可以对泛型参数添加一些约束,以确保它符合某些结构。可以通过中类型参数上设置extends 约束来实现
  5. 类型推断与默认类型:typeScript的类型推断机制可以自动推断泛型类型参数;泛型类型可以设置默认类型
typescript 复制代码
//泛型函数
function startClass<T,U>(name:T,score:U):T{
  return name + score
}

console.log(startClass(<string,number>('yy',5)))

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;
}

// 泛型接口
interface GenericIdentityFn<T> {
    (arg: T): T;
}
function identityFn<T>(arg: T): T {
    return arg;
}
let myIdentity: GenericIdentityFn<number> = identityFn;


// 泛型约束
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // 现在我们可以访问.length属性了
    return arg;
}

// 使用泛型约束
loggingIdentity({length: 10, value: 3});
2.装饰器 - decorator

在 TypeScript 中,装饰器是一种特殊类型的声明,它可以被附加到类声明、方法、访问符、属性或参数上。装饰器使用 @expression 的形式,其中 expression 必须在运行时求值为一个函数,它将在编译时调用,

装饰器可以使用在许多不同的上下文中,但它们的主要用途是修改类的行为,为类添加元数据,或者为类、方法、属性等提供额外的功能。

typescript 复制代码
function Roo(target:Function):void{
  // 拿到的类
  target.prototype.startClass = function():void{
    // 逻辑
  }
}

// 类装饰器
@@Roo
class Course {
  constructor(){
    // 业务逻辑
  }
}

// 属性装饰器
function nameWrapper(target:any,key:string){
  // 逻辑处理
  Object.defineProerty(target,key){
    // 数据劫持
  }
}

class Course {
  constructor(){
    // 业务逻辑
  }
  @nameWrapper
  public name:string
}
相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰8 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪8 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪8 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy9 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom10 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom10 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试