当前位置:网站首页 > TypeScript编程 > 正文

TypeScript 基础类型系统_typescript基本数据类型

目录

  1. 基础类型
  2. 联合类型
  3. 交叉类型
  4. 函数(参数与返回值, 剩余参数, 可选参数, 推导方式, 重载)
  5. 类/抽象类

基础类型

TypeScript 基础类型有 12 种分别为 number, string, boolean, array, tuple, undefined, null, void, never, object, symbol, bigint. 接下来每个类型我都会举2~3个例子来让你明白该类型的作用

number 数字类型

TS 的数字类型是包含 小数的, 也就是说 TypeScrpit 并没有 浮点类型, 这是因为 TS 只是一个 只有做静态检查 并没有在底层做 内存分配 检查完毕后最终还是要 编译 为 JS

let a: number = 10;

let b: number = 10.1;

console.log(a); // 10

console.log(b); // 10.1

string 字符串类型

字符串类型在 TS 中使用与 number 类似

let s1: string = 'str';

console.log(s1); // str

boolean 布尔类型

布尔类型在 TS 中只能是 true 或 false

let b: boolean = true;

let b1: boolean = false;

// let b2: boolean = 1; // error

array 数组

数组中元素类型可以不唯一, 也无需定义 长度

// 单类型数组定义(表示数组中只能存储 数字类型)
let arr: number[] = [1, 2, 3];

// 多类型数组(数组可以存储 数值, 字符串, 布尔 类型)
let arr1: (number | string | boolean)[] = [1, 2, '2', true, 3];

// 通过泛型来定义数组(先知道, 后续学到泛型会在看到)
let arr2: Array<string | number> = [1, '2', 3];

console.log(arr2);

arr1.push(6);

arr1.pop();

console.log(arr1);

tuple 元组

元组与数组的区别: 元组是由一组相同类型且固定长度数组 组成 元组特点:

  1. 元组可以调用数组方法, 理论上 通过 类型推导结果是无法完成 push,pop,reverse 这些操作的, 但是 TS 最终还是变为 JS 也就是说最终是这三个操作都成功执行
let tuple: [string, number, boolean] = ['1', 2, true];

tuple.push(1);
// tuple[3]; // error 因为长度已经固定, 所以理论上是无法添加
tuple.pop();
tuple.pop();
tuple[2]; // 因为长度是固定的
tuple.reverse();
// 这是 tuple 的 类型推导结果 let tuple: [string, number, boolean]
tuple;

Enum 枚举

枚举

枚举分类: 枚举, 常量枚举(性能更加优秀), 异构枚举 我们先从 枚举入手, 枚举编译出来后就是一个对象, 枚举的原理: 是根据上一个枚举元素来推断下一个枚举元素(我们看最终编译结果即可得知), 枚举还可以划分为 正0举(通过枚举元素访问)/反举(通过索引访问)

enum OPERATOR_TYPE {
  DELETE, // 删除 => 0
  RECYCLE, // 移动到回收站 => 1
  CREATED, // 创建 => 2
  UPDATE, // 更新 => 3
  RESTORE = "RESTORE", // 恢复 => RESTORE
  // STORE // 错误, 枚举是根据上一个值进行推断的
}

// 正举
console.log(OPERATOR_TYPE.RECYCLE); // 1
console.log(OPERATOR_TYPE.DELETE); // 0

// 反举
console.log(OPERATOR_TYPE[0]); // DELETE

Pasted image 20240922163450.png

常量枚举

为何说常量枚举性能更加优异呢? 这是因为 常量枚举并不会生成一个对象, 常量枚举更加接近于 编译宏 这个概念, 在编译时将 枚举值 直接替换到 对应位置

const enum OPERATOR_TYPE {
  DELETE, // 删除 => 0
  RECYCLE, // 移动到回收站 => 1
  CREATED, // 创建 => 2
  UPDATE, // 更新 => 3
  RESTORE = "RESTORE", // 恢复 => RESTORE
}

// 不能直接访问 OPERATOR_TYPE 会抛出错误
// 将枚举值直接替换到 下面这些位置中
console.log(OPERATOR_TYPE.DELETE);
console.log(OPERATOR_TYPE.RECYCLE);
console.log(OPERATOR_TYPE.CREATED);
console.log(OPERATOR_TYPE.UPDATE);
console.log(OPERATOR_TYPE.RESTORE);

Pasted image 20240922164215.png

异构枚举

异构枚举就是 枚举集合中拥有多个类型的枚举

enum OPERATOR_TYPE {
  DELETE,
  RECYCLE,
  CREATED = 'CREATED'
}

console.log(OPERATOR_TYPE.DELETE);
console.log(OPERATOR_TYPE.RECYCLE);
console.log(OPERATOR_TYPE.CREATED);

undefined 与 null

undefined 与 null 是 所有类型的 子类型, 什么叫做 子类型呢? 就是说 我们可以给 任意类型赋值为 undefined 或 null, 但是前提是需要将 tsconfig.json 中的严格检查关闭, TS 中默认为 严格检查模式

let n1: number = null;
let s1: string = null;
let b1: boolean = null;
let ns2: number[] = null;

let n2: number = undefined;
let s2: string = undefined;
let b2: boolean = undefined;
let ns3: number[] = undefined;

void 空值返回

void 一般作用于函数返回值的定义, 函数定义一般不会是 undefined 而是选择 void

// 一般不推荐使用 funciton getVal(): undefined {...}
// VsCode 默认返回值为 void
function getVal1() {

}
function getVal(): void {
  console.log('this method return typeof value is void');

  // return undefined;
  return;
}

never

never 同样也是任意类型的子类型, 但是 never 我觉得更加适用与 fallback(备用) 兜底类型/备用类型 never 在哪些情况下使用呢?

  1. 当程序无法执行到终点时?
  2. 类型保护(也可以叫做 fallback, 兜底类型/备用类型) 什么叫做程序无法执行到终点呢?
// 抛出错误, 程序就被重点 无法执行到重点
function getVal(): never {
	throw new Error();
}
// 程序无法进入下一步
function loop(): never {
	while(true) {}
}

类型保护

function validate(value: never) {
  throw new Error(value);
}

  

function getValue(value: string | number | boolean) {
  if(typeof value === 'string') {
    return value;
  }
  

  if(typeof value === 'number') {
    return value;
  }
  
  if(typeof value === 'boolean') {
    return value;
  }

  validate(value);
}

object

object 可以使用三种方式定义: Object/{}/object, 但是推荐使用 第三种方式, 我们来单独说说三种的区别吧!

  1. Object 用于描述类, 同时还可以使用点语法调用 Object.prototype 的方法,他与 any 的范围是有些相似的, Object 将范围扩展非常大, 除 undefined,null 以外都可以赋值(在严格模式下, 不检查 null 情况下则不会抛出错误)
  2. 使用 {} 一般用于赋值 空对象, 但是非常少用
  3. object 是我们最常用的, 常用于 定义较大范围的一个值
let obj: {} = {};

// let obj1: Object = null; // error
let obj2: any = null;

function create(value: object) {}
create([]);
create({});
create(function() {});

symbol 符号类型

symbol 较为少用, 作用为 创建唯一的一个值, 当然也可以使用 .for 方法设置非唯一值

let s: symbol = Symbol('123');
let s1: symbol = Symbol('123');
console.log(s === s1); // false
  

let s2: symbol = Symbol.for('123');
let s3: symbol = Symbol.for('123');
console.log(s2 === s3); // true

bigint 大范围整数

  1. 用于创建 超出 Number 最大值范围的整数
console.log(Number.MAX_VALUE);
console.log(Number.MAX_SAFE_INTEGER);

let b: bigint = BigInt(Number.MAX_VALUE);
let b1: bigint = BigInt(Number.MAX_SAFE_INTEGER);

console.log(b);
conosle.log(b1);

[[any]] 任意类型

any 特点就是 绕过类型检测

let a: any = 123;
let a1: any = '123';
let a2: any = true;
let a3: any = function () {};
let a4: any = [];
let a5: any = {};
let a6: any = Symbol('123');
let a7: any = Symbol.for('123');
let a8: any = BigInt(Number.MAX_SAFE_INTEGER);
let a9: any = { 0: 1, length: 1, splice: Array.prototype.splice };

字面量类型(这是一个特殊的类型)

字面量类型一般是使用 const 来定义而转变为 字面量类型, 但是你也可以手动声明类型 将其字面量类型转换为 你所定义的 目标类型

const a = 10; // 类型推断为 10

const b = 'str'; // 类型推断为 str

const c = true; // 类型推断为 true

const d = {}; // 类型推断为 {}

const e = []; // 类型推断为 []

const f = function() {}; // 类型推断为 () => void

公共方法

在 TS 中公共方法就是 多种类型都有的一个方法, 就好比 number,string,boolean,array,object,funciton 都有 toString 方法, 那么 toString 就是一个公共方法

let a: number | string;

a.toString();

断言

断言的作用 就是 让 TS 依附于你的 建议, 你认为该值的类型是什么 那么就是什么, 但出现问题你应该负责, 断言分为四大类

  1. 非空断言: 认定该值一定不是空, 使用 ! 进行断言
const ele = document.getElementById('ele')!; // 认定你获取的 DOM 元素一定不为空
  1. as 断言/类型断言: 将一种不确定的类型转换为一个确定的类型, 也可以认为是 类型收缩/类型缩小
const ele = document.getElementById('ele');

(ele as HTMLElement).style.display = 'none';
  1. 类型断言: 使用类似与泛型的写法即可进行类型断言, 同属于类型收缩
const ele = document.getElementById('ele');

(<HTMLElement>ele!).style.background = 'red';
  1. 双重断言: 当一个类型无法兼容你需要转换的类型时, 即可使用双重断言
const ele = document.getElementById('ele');

(ele as any) as number; // 这是一个不合理的操作, 但这只是为了演示

联合类型/自定义类型

联合类型是将 多种类型 合并为一种类型, 常用于构建 新的 复杂类型 我们将定义一个由 多个字符串 组成的一个类型

type ACTION = 'up' | 'down' | 'left' | 'right';

let action: ACTION = 'up';

属性互斥, 使用联合类型我们可以定义一个 互斥类型, 根据一个值来确定一个对象的类型

type IPerson = {
  name: 'Xiao',
  [K: string]: any
} | {
  name: 'Lin',
  [K: string]: any
}

const Xiao: IPerson = {
  name: 'Xiao',
  age: 16
}

const Lin: IPerson = {
  name: 'Lin',
  age: 16
}

交叉类型

交叉类型就是将其取交集, 一般用于将 对象合并

interface IPerson {
  name: string;
}

interface ISkill {
  skill: string[];
}

interface IHobby {
  hobby: string[];
}


type INewPerson = IPerson & ISkill & IHobby;
  
let newPerson: INewPerson = {
  name: 'Xiao',
  skill: ['C/C++', 'JavaScript', 'Rust'],
  hobby: ['Running', 'Learning', 'reading', 'finance'],
}

函数类型

函数定义类型注解两种方式

从宏观来说我们的函数定义就两种方式 一种直接通过 function 关键字来定义, 一种是 函数表达式, 所以我们有两种定义方式相同的 注解也有两种定义方式

// 函数本身进行注解
function test(a: number, b: number): number {
  return a + b;
}

// 定义函数实现或类型别名
type ITest = (x: number, b: number) => number;

const test1: ITest = (a, b) => {
  return a + b;
}

参数注解

参数注解就是给函数参数 添加类型注解从而来限定 用于限定用户传入的参数

function test(a: string, b: string) {
  return a + b;
}

可选参数

可选参数原理与函数默认值 不可并存, 添加可选参数就是给参数设置 用户设置类型 | undefined 可选参数特点:

  1. 与函数默认值不可并存
  2. 可选参数 后面不可在有参数
// VsCode 推断的类型为 b => string | undefined, c => boolean | undefined
function test(a: number, b?: string, c?: boolean) {}

// 可选参数后面还跟则 参数
// function test1(a: string, b?: number, c: boolean) {} // error

剩余参数

%% 需要添加剩余参数 引用 %% [[剩余参数]] 剩余参数为一个数组, 需要定义的类型为 类型数组

function test(a: number, ...rest: number[]) {}

返回类型设置

函数返回类型若是为 void 则表示 不关心其返回类型(但是这只能基于 [[TS 推导方式#根据上下文自动推导]] 的方法进行使用)

type ITest = (x: number, y: number) => void;

const test: ITest = (a, b) => {
  return a + b;
};

test(1, 2);

函数 this 指向

若是需要让函数中使用并将 this 指向目标, 需要将 this 定义在第一项 [[keyof 的使用]] [[typeof 的作用]]

const obj = {
  name: 'Xiao',
  age: 20
}

type IObj = typeof obj;

function getVal(this: IObj, key: keyof IObj) {
  return this[key];
}

getVal.call(obj, 'name');

函数重载

重载的定义就是 参数个数或参数类型不同时 重载就会产生 TS 中的重载并不是 真正的重载而是 伪重载 只重载类型 不重载逻辑, TS 重载的作用其实最重要的就是让TS类型推断更加精确让编辑器提示更加准确

function toArray(n: number): number[];
function toArray(n: string): string[];
function toArray(n: number | string): number[] | string[] {
  if(typeof n === 'number') {
    return n.toString().split('').map(Number);
  } else {
    return n.split('');
  }
}
  
const arrNum = toArray(123); // 推断为 number[]
const arrStr = toArray('123'); // 推断为 string[]

总结

  1. 函数我们主要学习 参数注解, 可选参数, 剩余参数, 返回类型设置, this, 函数重载

构造器

TS 构造器初始化方式分为两种,一种是 先定义在赋值, 后者是 一体化赋值

  1. 先定义在赋值
class Person {
  public name: string;
  public age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
  1. 一体化赋值
class Person {
  // 一体化赋值
  constructor(     public name: string,     public age: number   ) {}
}

修饰符

修饰符的作用是决定 属性/方法 是否可见, 属性修饰符可以分为以下四类:

  1. public: 公共(谁都可以进行 操作)(同时也是 默认的修饰符, 若是定义 属性/方法 不定义则默认为 public)
  2. protected: 受保护(仅允许 当前类或子类进行 操作)
  3. private: 私有(仅允许当前类进行 操作)
class Person {
  constructor(     public name: string,     protected age: number,     private skill: string   ) {}
}

class Xiao extends Person {
  constructor(name: string, age: number, skill: string) {
    super(name, age, skill);
    console.log(this.name);
    console.log(this.age);
    // console.log(this.skill); // 无法访问, 因为仅有 Person 可以访问
  }
}

实例属性/方法

定义实例属性/方法 默认的类型修饰符都为 public

class Person {
  // 定义实例属性
  public inst:string = "PersonInst";
  // 定义实例方法
  public getName: () => string = function(this: any) {
    return this.name || 'name is null';
  }

  constructor(     public name: string,     public age: number   ) {}
}

const p = new Person('Xiao', 20);
console.log(p);

原型方法

class Person {
  constructor(     public name: string,     public age: number   ) {}
  
  // 定义原型方法(默认为 public)
  getName() {
    return this.name;
  }
}

静态属性

class Person {
  constructor(     public name: string,     public age: number   ) {}

  static getVal() {
    return this.personName;
  }
  
  static personName: string = "PERSON";
}

Person.getVal(); // PERSON

属性访问器

class Person {
  constructor(     public name: string,     public age: number,     private _skill: string   ) {}
  
  // 属性访问器
  get skill(): string[] {
    return this._skill.split(',');
  }

  set skill(value: string) {
    this._skill = value;
  }
}
  
const p = new Person('Xiao', 20, 'JS,C,English,Math');
console.log(p);
console.log(p.skill);

类方法重载

class Person {
  getName(value: string) : string;
  getName(value: string[]): string;
  getName(value: string | string[]): string {
    if(typeof value === 'string') {
      return 'value | ' + value;
    } else {
      return 'value[] |' + value.join(',');
    }
  }
}

const p = new Person();
p.getName('1');
p.getName(['test', 'test1']);

继承/重写

实例,静态,原型,属性访问器 等 都可以继承 重写注意点:

  1. 类型需要兼容, 父类若返回类型设置 void 则表示不关心其返回值
class Person {
  private _computer: string = "";
  constructor(public name: string, public age: number) {}
  
  get computer() {
    return this._computer;
  }
  
  set computer(value) {
    this._computer = value;
  }

  static value: string = "Person";

  static getVal() {
    return this.value;
  }

  // 父类若是声明 void 则表示 不关心 子类的返回值, 但是
  getVal(): void {
    console.log('person name', this.name);
  }
}

class Xiao extends Person {
  constructor(name: string, age: number) {
    super(name, age);
  }

  // 子类重写父类 需要让 子类类型兼容父类(若是父类有参数)
  getVal() {
    return this.name;
  }
  static value: string = "Xiao";
}

const xiao = new Xiao('Xiao', 20);
xiao.computer = 'M';
console.log(xiao.computer); // M
console.log(xiao.getVal()); // Xiao
console.log(Xiao.getVal()); // Xiao

抽象类

抽象类是用于 给子类提供一个 统一的接口或框架 抽象类特点:

  1. 不可被new
  2. 可以包含方法具体实现, 但是抽象提供的接口则一定需要 实现
abstract class Animal {
  abstract eat(): void;
  // 注意该方式是定义实例方法
  abstract run: () => void;
  drank(): string {
    return 'drank';
  }
}


class Tiger extends Animal {
  eat(): void {
    throw new Error("Method not implemented.");
  }

  run: () => void = () => {};
}

const tiger = new Tiger();

tiger.drank(); // drank

使用场景: 当父类不想要被 new 时即可使用

绕过 TS 类型检查

  1. 使用 [] 语法即可绕过 TS 对 类修饰符的检测
class Person {
  constructor(     private name: string   ) {}
}

const p = new Person('Xiao');
// p.name // 错误
console.log(p['name']); // xiao

总结

  1. 基础类型: number,string,boolean,array,tuple,undefined,null,never,void,object,symbol,bigint
  2. 枚举: 枚举,常量枚举
    1. 枚举: 编译后形成对象
    2. 常量枚举: 类似 C 语言中的编译宏 概念, 编译出来直接将值 填入对应位置, 性能更加优异
    3. 枚举可以使用 正举(通过枚举元素访问)/反举(通过索引访问)
  3. 交叉类型: 交叉类型一般用于 合并对象
  4. 联合类型: 联合类型用于 产生一个新类型
  5. 函数(剩余/可选 参数,返回值, 重载, 自动推导):
    1. 推导方式: 根据值推导,根据返回值推导,根据位置推导
    2. 可选参数与参数默认值只能任选其一
    3. 函数重载 其目的就是为了 让编辑器推断更加精确
  6. 类/抽象类
    1. 构造函数中可以使用 一体化赋值
    2. 参数修饰符: pubilc(函数与参数默认修饰符),protected,private(可以使用 []绕过私有属性检查)
    3. 类方法仍然可以进行重载
    4. 抽象类: 当父类不想被 new 时即可使用 抽象类, 抽象类所预定义的函数/实例 接口必须被实现

推荐观看(扩展阅读):

  1. any/unknown/never 区别
  2. TS 推导方式

版权声明


相关文章:

  • 【二】用Vue3+Typescript+nodejs实现个人信息模块_vue个人信息页面2024-10-30 13:17:43
  • Vue3 + TypeScript 实现 iframe 嵌入与通信的完整指南以及全屏弹窗方案_vue iframe onload2024-10-30 13:17:43
  • TypeScript 的基本概念、类型以及与 JavaScript 的关系(个人学习向)_typescript和javascript哪个更好2024-10-30 13:17:43
  • TypeScript要被淘汰_typescript有必要学吗2024-10-30 13:17:43
  • typescript 后端开发_怎么开发一个软件2024-10-30 13:17:43
  • typescript 重温2024-10-30 13:17:43
  • typescript type_typescript高级类型声明2024-10-30 13:17:43
  • 5.typeScript中的类2024-10-30 13:17:43
  • 3 .typeScript中的函数2024-10-30 13:17:43
  • 1.TypeScript安装及介绍2024-10-30 13:17:43
  • 全屏图片