目录
- 基础类型
- 联合类型
- 交叉类型
- 函数(参数与返回值, 剩余参数, 可选参数, 推导方式, 重载)
- 类/抽象类
基础类型
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 元组
元组与数组的区别: 元组是由一组相同类型且固定长度数组 组成 元组特点:
- 元组可以调用数组方法, 理论上 通过 类型推导结果是无法完成 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
常量枚举
为何说常量枚举性能更加优异呢? 这是因为 常量枚举并不会生成一个对象, 常量枚举更加接近于 编译宏 这个概念, 在编译时将 枚举值 直接替换到 对应位置
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);
异构枚举
异构枚举就是 枚举集合中拥有多个类型的枚举
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 在哪些情况下使用呢?
- 当程序无法执行到终点时?
- 类型保护(也可以叫做 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, 但是推荐使用 第三种方式, 我们来单独说说三种的区别吧!
- Object 用于描述类, 同时还可以使用点语法调用 Object.prototype 的方法,他与 any 的范围是有些相似的, Object 将范围扩展非常大, 除 undefined,null 以外都可以赋值(在严格模式下, 不检查 null 情况下则不会抛出错误)
- 使用 {} 一般用于赋值 空对象, 但是非常少用
- 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 大范围整数
- 用于创建 超出 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 依附于你的 建议, 你认为该值的类型是什么 那么就是什么, 但出现问题你应该负责, 断言分为四大类
- 非空断言: 认定该值一定不是空, 使用
!
进行断言
const ele = document.getElementById('ele')!; // 认定你获取的 DOM 元素一定不为空
- as 断言/类型断言: 将一种不确定的类型转换为一个确定的类型, 也可以认为是 类型收缩/类型缩小
const ele = document.getElementById('ele');
(ele as HTMLElement).style.display = 'none';
- 类型断言: 使用类似与泛型的写法即可进行类型断言, 同属于类型收缩
const ele = document.getElementById('ele');
(<HTMLElement>ele!).style.background = 'red';
- 双重断言: 当一个类型无法兼容你需要转换的类型时, 即可使用双重断言
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
可选参数特点:
- 与函数默认值不可并存
- 可选参数 后面不可在有参数
// 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[]
总结
- 函数我们主要学习 参数注解, 可选参数, 剩余参数, 返回类型设置, this, 函数重载
类
构造器
TS 构造器初始化方式分为两种,一种是 先定义在赋值, 后者是 一体化赋值
- 先定义在赋值
class Person {
public name: string;
public age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
- 一体化赋值
class Person {
// 一体化赋值
constructor( public name: string, public age: number ) {}
}
修饰符
修饰符的作用是决定 属性/方法 是否可见, 属性修饰符可以分为以下四类:
- public: 公共(谁都可以进行 操作)(同时也是 默认的修饰符, 若是定义 属性/方法 不定义则默认为 public)
- protected: 受保护(仅允许 当前类或子类进行 操作)
- 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']);
继承/重写
实例,静态,原型,属性访问器 等 都可以继承 重写注意点:
- 类型需要兼容, 父类若返回类型设置 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
抽象类
抽象类是用于 给子类提供一个 统一的接口或框架 抽象类特点:
- 不可被new
- 可以包含方法具体实现, 但是抽象提供的接口则一定需要 实现
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 类型检查
- 使用 [] 语法即可绕过 TS 对 类修饰符的检测
class Person {
constructor( private name: string ) {}
}
const p = new Person('Xiao');
// p.name // 错误
console.log(p['name']); // xiao
总结
- 基础类型: number,string,boolean,array,tuple,undefined,null,never,void,object,symbol,bigint
- 枚举: 枚举,常量枚举
- 枚举: 编译后形成对象
- 常量枚举: 类似 C 语言中的编译宏 概念, 编译出来直接将值 填入对应位置, 性能更加优异
- 枚举可以使用 正举(通过枚举元素访问)/反举(通过索引访问)
- 交叉类型: 交叉类型一般用于 合并对象
- 联合类型: 联合类型用于 产生一个新类型
- 函数(剩余/可选 参数,返回值, 重载, 自动推导):
- 推导方式: 根据值推导,根据返回值推导,根据位置推导
- 可选参数与参数默认值只能任选其一
- 函数重载 其目的就是为了 让编辑器推断更加精确
- 类/抽象类
- 构造函数中可以使用 一体化赋值
- 参数修饰符: pubilc(函数与参数默认修饰符),protected,private(可以使用
[]
绕过私有属性检查) - 类方法仍然可以进行重载
- 抽象类: 当父类不想被 new 时即可使用 抽象类, 抽象类所预定义的函数/实例 接口必须被实现
推荐观看(扩展阅读):
- any/unknown/never 区别
- TS 推导方式
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/typescriptbc/1312.html