【前端工程化】TypeScript概念及使用

前端工程化(2)- TS

在这里插入图片描述

文章目录

    • 前端工程化(2)- TS
    • TS
      • 概念
      • TS声明变量方式
      • TS的类
        • 访问修饰符
        • 静态属性
        • 抽象类
      • TS的数据类型
        • tuple元祖
        • enum枚举
        • any
        • void
        • never
      • enum枚举
        • 使用例子
        • 反向映射
        • 枚举和常量枚举(const枚举)的区别
      • 接口
      • 泛型
      • 高级类型

TS

概念

TypeScript 是一个强类型的 JavaScript 超集,支持ES6语法,支持面向对象编程的概念,如类、接口、继承、泛型等。Typescript并不直接在浏览器上运行,需要编译器编译成纯Javascript来运行。

添加了静态类型,更利于构建大型应用:
因为有类型约定,减少了在写代码的时候出现错误,而且出现问题后更容易查错。
代码更清晰,某种程度可以看作文档,后面新人接手项目能更快上手。

TS声明变量方式

// 声明类型和值
let name: type = value;

// 只声明类型
let name: type;

// 只声明值(类型隐式添加上了)
let name = value;

// 声明变量无类型和值
let name;

TS的类

类是面向对象程序设计实现信息封装的基础。
JS基于原型的方式让开发者多了很多理解成本。在ES6之后,JS拥有了class关键字(本质依然是构造函数),但是JS的class依然有一些特性没有加入,比如修饰符和抽象类。TS的class支持面向对象的所有特性,比如接口等。

访问修饰符

public,表示属性或方法是公共的,可以在任何地方访问。
protected,表示属性或方法是受保护的,可以在类内部和子类中访问。
private,表示属性或方法是私有的,只能在类内部访问。
readonly,属性设置为只读,只读属性必须在声明时或构造函数里被初始化。
TypeScript 中的修饰符主要在编译阶段进行检查,而 JavaScript 运行时并不支持这些修饰符。

class Animal {
  public name: string; // 默认为 public
  private age: number; // 私有属性,只能在类内部访问
  protected sound: string; // 受保护的属性,可以在子类中访问

  constructor(name: string, age: number, sound: string) {
    this.name = name;
    this.age = age;
    this.sound = sound;
  }

  public makeSound(): void {
    console.log(`${this.name} says ${this.sound}`);
  }

  private getAge(): number {
    return this.age;
  }

  protected showAge(): void {
    console.log(`${this.name} is ${this.getAge()} years old.`);
  }
}

class Dog extends Animal {
  constructor(name: string, age: number) {
    super(name, age, 'Woof');
  }

  public bark(): void {
    console.log(`${this.name} barks loudly!`);
    // 在子类中可以访问 protected 属性和方法
    this.showAge();
  }
}

const cat = new Animal('Whiskers', 3, 'Meow');
cat.makeSound(); // 可以访问 public 方法
// cat.age; // 编译错误,无法访问 private 属性

const dog = new Dog('Buddy', 2);
dog.makeSound(); // 可以访问从父类继承来的 public 方法
// dog.showAge(); // 编译错误,受保护的方法只能在子类内部访问
dog.bark(); // 可以访问子类的 public 方法
静态属性

这些属性存在于类本身上面而不是类的实例上,通过static进行定义,访问这些属性需要通过 类型.静态属性 的这种形式访问

class Square {
    static width = '100px'
}

console.log(Square.width) // 100px

上述的类都能发现一个特点就是,都能够被实例化。TS中还有一种不会被实例化的抽象类。

抽象类

抽象类做为其它派生类的基类使用,它们一般不会直接被实例化,不同于接口,抽象类可以包含成员的实现细节。

// abstract 关键字是用于定义抽象类和在抽象类内部定义抽象方法
abstract class Animal {
    abstract makeSound(): void;
    move(): void {
        console.log('roaming the earch...');
    }
}

// 这种类并不能被实例化,通常需要我们创建子类去继承
class Cat extends Animal {

    makeSound() {
        console.log('miao miao')
    }
}

const cat = new Cat()

cat.makeSound() // miao miao
cat.move() // roaming the earch...

TS的数据类型

TS兼容JS,拥有JS相同的数据类型,另外在JS基础上提供了更多的类型。
在开发阶段,可以为明确的变量定义为某种类型,这样typescript就能在编译阶段进行类型检查,当类型不合符预期结果的时候则会出现错误提示。

boolean(布尔类型)number(数字类型)string(字符串类型)array(数组类型)object 对象类型 null 和 undefined 类型
tuple(元组类型)enum(枚举类型)any(任意类型)void 类型 never 类型

tuple元祖

元祖类型,允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
赋值的类型、位置、个数需要和定义(生明)的类型、位置、个数一致。

let tupleArr:[number, string, boolean];
tupleArr = [12, '34', true]; //ok
typleArr = [12, '34'] // no ok
enum枚举

下面再详细描述。

any

可以指定任何类型的值,在编程阶段还不清楚类型的变量指定一个类型,不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查,这时候可以使用any类型。

let num:any = 123;
let arrayList: any[] = [1, false, 'fine'];
void

用于标识方法返回值的类型,表示该方法没有返回值。

function hello(): void {
    alert("Hello Runoob");
}
never

never是其他类型 (包括null和 undefined)的子类型,可以赋值给任何类型,代表从不会出现的值。
但是没有类型是 never 的子类型,这意味着声明 never 的变量只能被 never 类型所赋值。
never 类型一般用来指定那些总是会抛出异常、无限循环。

let a:never;
a = 123; // 错误的写法

a = (() => { // 正确的写法
  throw new Error('错误');
})()

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}

enum枚举

枚举主要是将一些预定义的值显示的表达出来。它的优势是更加语义化,并更好维护。
在工作中也经常用,比如定义一些后端传回的错误码,就会用枚举把数字变成更好读的枚举名称。比如规定一些key的值,在不同地方使用的时候统一用枚举,减少拼错等BUG的可能性,也和后端更好对接。

使用例子

todo 在项目里找一下很多。

反向映射

反向映射只适用于数字枚举。字符串枚举等没有反向映射。
当我们声明一个枚举类型是,虽然没有给它们赋值,但是它们的值其实是默认的数字类型,而且默认从0开始依次累加:

enum Direction {
    Up,   // 值默认为 0
    Down, // 值默认为 1
    Left, // 值默认为 2
    Right // 值默认为 3
}

console.log(Direction.Up === 0); // true

正向映射( name -> value )和反向映射( value -> name )
console.log(Direction[0]); // Up

枚举和常量枚举(const枚举)的区别

枚举会被编译时会编译成一个对象,可以被当作对象使用;
const枚举会在ts编译期间被删除,避免额外的性能开销;

// 普通枚举
enum Witcher {
  Ciri = 'Queen',
  Geralt = 'Geralt of Rivia'
}
function getGeraltMessage(arg: {[key: string]: string}): string {
  return arg.Geralt
}
getGeraltMessage(Witcher) // Geralt of Rivia

// const枚举
const enum Witcher {
  Ciri = 'Queen',
  Geralt = 'Geralt of Rivia'
}
const witchers: Witcher[] = [Witcher.Ciri, Witcher.Geralt]
// 编译后
// const witchers = ['Queen', 'Geralt of Rivia'

接口

接口可以用于定义对象、函数、类等的类型。

定义对象的结构:

interface Person {
  firstName: string;
  lastName: string;
  age?: number; // 可选属性
}

// 符合接口结构的对象
let person: Person = {
  firstName: "John",
  lastName: "Doe"
};


定义函数类型:
interface GreetFunction {
  (greeting: string, name: string): string;
}

let greet: GreetFunction = function (greeting, name) {
  return `${greeting}, ${name}!`;
};


定义类的接口:
interface Shape {
  area(): number;
}

class Circle implements Shape {
  radius: number;

  constructor(radius: number) {
    this.radius = radius;
  }

  area(): number {
    return Math.PI * this.radius ** 2;
  }
}


可扩展的对象结构:
interface Car {
  brand: string;
  model: string;
  // 允许添加其他属性
  [key: string]: any;
}


可以继承:
interface Father {
    color: String
}

interface Mother {
    height: Number
}

interface Son extends Father,Mother{
    name: string
    age: Number
}

在多人开发的时候有对象属性类型约束或者有函数输入输出类型约束,可以提高效率避免BUG。

泛型

泛型就是把类型当成变量。定义函数,接口或者类的时候,不预先定义好具体的类型,而在使用的时候在指定类型。
在泛型中,类型参数写在左括号(<)和右括号(>)之间。

接收什么类型的参数返回什么类型的参数,即在运行时传入参数我们才能确定类型:
function identity<T>(arg: T): T {
  return arg;
}
let output1 = identity<string>("CoderBin");
let output2 = identity<number>( 117 );

定义泛型的时候,可以一次定义多个类型参数,比如我们可以同时定义泛型 T 和 泛型 U:

function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}

swap([7, 'seven']); // ['seven', 7]

接口声明

interface ReturnItemFn<T> {
    (para: T): T
}

const returnItem: ReturnItemFn<number> = para => para

类声明

class Stack<T> {
    private arr: T[] = []

    public push(item: T) {
        this.arr.push(item)
    }

    public pop() {
        this.arr.pop()
    }
}

const stack = new Stacn<number>()

泛型约束:如果泛型只能传递 string 和 number 类型,这时候就可以使用 的方式猜实现约束泛型。
type Params = string | number
class Stack {
}

高级类型

交叉类型和联合类型:
交叉类型:通过 & 将多个类型合并为一个类型,包含了所需的所有类型的特性,本质上是一种并的操作。
T & U
联合类型:表示其类型为连接的多个类型中的任意一个,本质上是一个交的关系。
T | U

类型别名:类型别名会给一个类型起个新名字,类型别名有时和接口很像,但是可以作用于原始值、联合类型、元组以及其它任何你需要手写的类型。
type some = boolean | string
const b: some = true // ok
可以是泛型
type Container = { value: T };

keyof:用于获取一个接口中Key的联合类型。

interface Button {
    type: string
    text: string
}

type ButtonKeys = keyof Button
// 等效于
type ButtonKeys = "type" | "text"

常用 keyof typeof obj

类型约束:通过关键字 extend 进行约束,不同于在 class 后使用 extends 的继承作用,泛型内使用的主要作用是对泛型加以约束。

type BaseType = string | number | boolean

// 这里表示 copy 的参数
// 只能是字符串、数字、布尔这几种基础类型
function copy<T extends BaseType>(arg: T): T {
  return arg
}

类型约束通常和类型索引一起使用,例如我们有一个方法专门用来获取对象的值,但是这个对象并不确定,我们就可以使用 extends 和 keyof 进行约束。

function getValue<T, K extends keyof T>(obj: T, key: K) {
  return obj[key]
}

const obj = { a: 1 }
const a = getValue(obj, 'a')

Omit 以一个类型为基础支持剔除某些属性,然后返回一个新类型。 语法如下

Omit<Type, Keys>

interface Todo {
  title: string
  description: string
  completed: boolean
  createdAt: number
}
type TodoPreview = Omit<Todo, "description">

Partial 可以快速把某个接口类型中定义的属性变成可选的

interface IUser {
  name: string
  age: number
  department: string
}

//经过 Partial 类型转化后得到

type optional = Partial<IUser>

// optional的结果如下

type optional = {
    name?: string | undefined;
    age?: number | undefined;
    department?: string | undefined;
}

Merge<O1, O2> 是将两个对象的属性合并。
Overwrite<T, U> 是用U的属性覆盖T的相同属性。
Exclude<T, U>的作用是将某个类型中属于另一个类型的移除掉

https://juejin.cn/post/7157149049714376735
https://juejin.cn/post/6988763249982308382
https://juejin.cn/post/7162011064819777567
https://juejin.cn/post/6999985372440559624
https://www.tslang.cn/docs/handbook/interfaces.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/475218.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文读懂融资融券交易技巧!在上海开融资融券账户交易利率一般是多少?

融资融券交易技巧包括以下几点&#xff1a; 熟悉股票市场&#xff1a;了解市场走势、公司基本面等信息&#xff0c;根据趋势选择合适的股票进行交易。 做好风险管理&#xff1a;对买卖的风险进行合理评估&#xff0c;设定止损价位&#xff0c;防止损失过大。 控制杠杆比例&am…

PowerShell 一键更改远程桌面端口

前言 提高工作效率,安全性和规范化,最终实现一键更改Windows 远程桌面端口 前提条件 开启wmi,配置网卡,参考 一键更改远程桌面端口自动化脚本 默认端口3389变更后的端口3390win+r mstsc YOU_ip常规更改的连接方式win+r mstsc YOU_ip:3390需要恢复到原来的端口3390更改成3…

【Linux笔记】汇编

汇编笔记 启动方式

IoT 物联网场景中 LoRa + 蓝牙Bluetooth 室内场馆高精定位技术全面解析

基于LoRa蓝牙的室内场景定位技术&#xff0c;蓝牙主要负责位置服务&#xff0c;LoRa主要负责数据传输。 01 LoRa和蓝牙技术 LoRa全称 “Long Rang”&#xff0c;是一种成熟的基于扩频技术的低功耗、超长距离的LPWAN无线通信技术。LoRa主要采用的是窄带扩频技术&#xff0c;抗干…

【spring】@Lazy注解学习

Lazy介绍 Lazy 注解是一个配置注解&#xff0c;用于指示 Spring 容器在创建 bean 时采用延迟初始化的策略。这意味着&#xff0c;除非 bean 被实际使用&#xff0c;否则不会被创建和初始化。 在 Spring 框架中&#xff0c;默认情况下&#xff0c;所有的单例 bean 在容器启动时…

如何在Ubuntu使用宝塔部署Emlog网站并发布到公网实现任意浏览器访问

文章目录 前言1. 网站搭建1.1 Emolog网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总结 前言 博客作为使…

5G网络架构与组网部署03--5G网络组网部署

1. SA组网与NSA组网 &#xff08;1&#xff09;NSA 非独立组网&#xff1a;终端同时接入4G基站和5G基站&#xff0c;只能实现5G部分功能 &#xff08;2&#xff09;SA组网【最终目标】&#xff1a;5G基站可以单独提供服务&#xff0c;接入的是5G核心网 区别&#xff1a;同一时间…

从0到1:Java构建高并发、高可用分布式系统的实战经验分享

文章目录 引言基础架构选择与设计微服务架构分布式储存与计算 高并发处理策略异步处理与消息队列并发控制与资源隔离 高可用性设计与故障恢复冗余与集群化容错与自我修复监控与运维自动化 引言 随着互联网业务的快速发展和技术迭代升级&#xff0c;作为Java架构师&#xff0c;…

yank+mermaid+甘特图实例

因为notion对于mermaid支持很一般&#xff0c;尤其是甘特图&#xff0c;如果时间跨度大、节点多&#xff0c;字号会小到看不见&#xff0c;非常不方便。 同样的代码&#xff0c;在notion中如下图所示&#xff1a;&#xff08;下图是我的一份年度规划&#xff09; &#xff08;…

【C++ leetcode 】双指针问题

1. 183. 移动零 题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 题目链接 . - 力扣&#xff08;LeetCode&#xff09; 画图 和 文字 分…

云效 AppStack + 阿里云 MSE 实现应用服务全链路灰度

作者&#xff1a;周静、吴宇奇、泮圣伟 在应用开发测试验证通过后、进行生产发布前&#xff0c;为了降低新版本发布带来的风险&#xff0c;期望能够先部署到灰度环境&#xff0c;用小部分业务流量进行全链路灰度验证&#xff0c;验证通过后再全量发布生产。本文主要介绍如何通…

九.pandas绘图基础

目录 九.pandas绘图基础 1-柱状图 --参数stackedTrue堆积 --参数figsize(宽,高) --自定义横坐标 --设置字体&显示负号 2.箱型图 3. 折线图 九.pandas绘图基础 Pandas的DataFrame和Series&#xff0c;在matplotlib基础上封装了一个简易的绘图函数, 使得我们在数据处…

刷题训练之滑动窗口

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握滑动窗口算法&#xff0c;并且能把下面的…

使用SourceTree获取git代码

1、在浏览器打开git的地址&#xff0c;并且使用用户名和密码登录&#xff1b; 2、输入你的git账号密码&#xff1b; 3、打开SourceTree&#xff0c;地址是自动带过来的&#xff0c;点击第二个“浏览”选择你在D盘或其它盘自己创建的文件夹&#xff1b; 4、正在拉代码&#…

GIT共享 跨仓库操作 子模块

初级代码游戏的专栏介绍与文章目录-CSDN博客 有些文件想在多个项目共享&#xff0c;但是又不能放在一个GIT仓库里&#xff0c;这要用到子模块&#xff08;submodule&#xff09;&#xff0c;说难不难&#xff0c;就是有些细节要注意。 不过说真的&#xff0c;共享向来不是个好主…

并发编程所需的底层基础

一、计算机运行的底层原理 1.多级层次的存储结构 ①:辅存 固态盘不是主要的应用对象&#xff0c;因为固态盘的使用次数是有限的&#xff0c;无法支撑高并发场景 磁盘存储的最基本原理是电生磁。 磁盘的磁道里边有很多的磁颗粒&#xff0c;磁颗粒上边有一层薄膜为了防止磁点氧…

Android VPN TLV协议场景使用

TLV协议格式是一种可变格式&#xff0c; TLV的意思就是&#xff1a;Type类型&#xff0c; Lenght长度&#xff0c;Value值&#xff1b; Type和Length的长度固定&#xff0c;一般那是2、4个字节&#xff1b; Value的长度有Length指定&#xff1b; 解析方法&#xff1a; 1.读取t…

C++ list详解及模拟实现

目录 本节目标 1. list的介绍及使用 1.2 list的使用 2.list的模拟实现 1.对list进行初步的实现 2.头插和任意位置的插入 3.pos节点的删除&#xff0c;头删&#xff0c;尾删 4.销毁list和析构函数 5.const迭代器 6.拷贝构造和赋值操作 3.完整代码 本节目标 1. list的…

Zookeeper的ZAB协议原理详解

Zookeeper的ZAB协议原理详解 如何保证数据一致性。 Paxos&#xff0c; 吸收了主从。 zk 数据模型Watch机制 zab zookeeper原子广播协议。 ZAB概念 ZooKeeper是通过Zab协议来保证分布式事务的最终一致性。 Zab(ZooKeeper Atomic Broadcast,.ZooKeeper原子广播协议)支持…