当前位置: 首页 > news >正文

TypeScript 高级类型

TypeScript 高级类型

1-类型别名

类型别名用来为类型起个新名字

type Name = string;
let nameValue: Name = "张三";
type Point = {
	x: number;
	y: number;
	add: (x: number, y: number) => number;
};

let point: Point = {x: 100, y: 200, add:(x: number, y: number) => x + y};

观察下面代码中存在的问题

let pizzaSize: 'large' | 'medium' | 'small' = 'medium'

function selectPizzaSize (size: 'large' | 'medium' | 'small') {
	pizzaSize = size
}
selectPizzaSize('small')

以上代码同一个类型被定义了多次 重复代码太多 可以使用 type 创建类型 复用类型

type Size = "large" | "medium" | "small";

let pizzaSize: Size = "medium";

function selectPizzaSize(size: Size) {
	pizzaSize = size
}

selectPizzaSize("large")

2-联合类型

联合类型可以把变量设置为多种类型

// 联合类型  为一个变量设置多个类型
let a: string | number | boolean = true
// arg 参数即可以是字符串类型也可以是数值类型
function fn(arg: string | number) {}
fn("a")
fn(10)

在使用联合类型的变量时 默认只能使用联合类型中所有类型中的公共属性 因为 TypeScript 编译器并不能确定它的具体类型是什么 所以不能准确的例出它的下面有哪些属性和方法
在这里插入图片描述
在使用联合类型的变量时通常需要先缩小变量的类型范围 这样编辑器能给出更加精准的代码提示
在这里插入图片描述
在这里插入图片描述
观察下面代码中存在的问题

// 披萨的大小
let pizzaSize: 'large' | 'medium' | 'small' = 'medium';

function selectPizzaSize (size: 'large' | 'medium' | 'small') {
	pizzaSize = size
};
selectPizzaSize("small");

以上代码同一个类型被声明了多次导致重复代码过多 可以使用 type 声明类型复用类型

type Size = 'large' | 'medium' | 'small';

let pizzaSiez: Size = 'medium';

function selectPizzaSize(size: Size) {
	pizzaSize = size
};
selectPizzaSize('large');

3-交叉类型

交叉类型是指把多个类型叠加合并组成新的类型 新类型中包含了被合并类型的所有属性

//type Draggable = {
//	drag:() => void;
//};

//type Resizable = {
//	resize: () => void;
//};

//type UIWidget = Draggable & Resizable;

//let textBox: UIWidget = {
//	drag: () => {},
//	resize: () => {},
//};

interface IPerson {
	id: string;
	age: number;
}
interface IWoeker {
	companyId: string;
}

type IStaff = IPerson & IWorker;
const staff: IStaff = {
	id: 'E1066',
	age: 33,
	companyId: 'EFT'
};
console.dir(staff)

在上面示例中 我们首先为IPerson和IWorker 类型定义了不同的成员 然后通过 & 运算符定义了 IStaff 交叉类型 所以类型同时拥有 IPerson 和 IWorker 这两种类型的成员

4-字面量类型

字面量类型是指字面量值得类型作为变量的类型 把字面量作为变量的取值范围

type Quan = 10;
let quan: Quan = 10;
type Quan = 10 | 100;
let quan: Quan = 1;
// 不能把类型 1 分配给类型 Quan
type Quan = "cm" | "inch";
let quan: Quan = "abc";
// 不能把类型 abc  分配给 Quan

在这里插入图片描述

5-可空类型

在TypeScript 中 undefined 和 null 这两个值本身也可以作为类型使用

let name: string;
name = "Marius";  // ok
name = null;      // ok
name = undefined; // ok

let age: number;
age = 24;    	  // ok
age = null;       // ok
age = undefined;  // ok


// undefined
let nothing: undefined = undefined;
// null 
let nothingMuch: null = null;


function greet(name: string | null | undefined) {
	if (typeof name === "string") {
		console.log(name.toLowerCase());
	}else {
		console.log("something went wrong");
	}
}

greet(undefined)

在严格的 null 检查模式中 null 和 undefined 不在分配给每个类型 null 和 undefined 现在都有自己的类型 每个类型只有一个值
在这里插入图片描述

6-可选链操作符

目标:掌握可选链操作符的使用方式
分析一段代码 javaScript 代码 为讲解可选链操作符做铺垫
可选链操作符和对象一起使用
可选链操作符和数组一起使用
可选链操作符和函数一起使用

先看一段 javaScript 中的代码 分析代码中的潜在问题

// person 对象中的 name 属性是可选的  即 person 对象中可能有 name 属性也可能没有 name 属性
// 如果 name 属性存在  它是字符串类型
const person = {name: "John"};
console.log(person.name.toUpperCase());  // JOHN
const person = {}
console.log(person.name.toUpperCase());


const person = {}
if (person.name) console.log(person.name.toUpperCase());

可选链操作符(?.)允许开发者安全的链式访问一个对象上可能为 null 或 undefined 的属性

可选链操作符和对象一起使用

interface Person{
	name?: string;
}

const person: Person = {name: "张三"};
person.name?.toLocaleUpperCase();

可选链操作符和数组一起使用

interface Person {
	skills: string[] | null;
}
const person: Person = {
	skills: ["编程", "开锁", "飞檐走壁"],
};

person.skills?.forEach((item) => console.log(item));

可选链操作符和函数一起使用

interface Person {
	sayHello?: () => void;
}
const person: Person = {
	sayHello: () => {
		alert("Hello");
	},
};
person.sayHello?.();

7-空值合并运算符

空值合并运算符(??)是一个逻辑运算符 当左侧的运算数为null 或者 undefined 时 返回其右侧运算数 否则返回左侧运算数

let speed: number | null = null;

let ride = {
	// speed: speed !== null ? speed: 30,
	speed: speed ?? 30,
}

8-类型断言

通过类型断言可以覆盖 TypeScript 编译器的推断 当开发者逼 TypeScript 更加清除它的类型时使用

// const phone: HTMLElement | null
const phon = document.getElementById("phone");

console.log((<HTMLInputElement>phone).value);
console.log((phone as HTMLInputElement).value);

类型断言 可以用来手动指定一个值得类型

类型断言的用途:
把一个联合类型断言为其中一个类型
把一个父类断言为更加具体的子类
把任何一个类型断言为 any
把 any 断言为一个具体的类型

类型断言只会影响 TypeScript 编译时的类型 类型断言语句在编译结果中会被删除

function toBoolean(something: any): boolean{
	return something as boolean;
}
toBoolean(1);
// 返回值 1
// 在上面例子中  把 something 断言为 boolean 虽然可以通过编译  但是并没有什么用  代码在编译后会变成
function toBoolean(something) {
	return something;
}
toBoolean(1)
// 返回值 1
// 所以类型断言不是类型转换  它不会真的影响到变量的类型

9-unknown类型

unknown 是严格的 any 类型 在对 unknown 类型的变量执行操作之前必须确定它的类型

let anything: unknown = "hello TypeScript";
anything = true;
anything = 3.14;
anything = function() {};

if (typeof anything === "number") {
	anything.toFixed();
}else if (typeof anything === "string") {
	anything.toUpperCase();
}else if (typeof anything === "function") {
	anything();
}

10-never类型

问题:对应一个接口 如何定义某个属性为 number 其它不确定的属性都为 string
在解决这个问题时 never 类型就可以派上大用场

interface IType {
	age: number;
	[key: string]: string;
}

这里要用到几个知识点
never 是任何类型的子类型 也就是说 never 可以赋值给任何类型

下面的两行代码 都不会有TS 错误

const a: number = "" as never;
const b: object = "" as never;


类型扩张
注意:有些地方叫 类型缩减 但是从表现出来的现象来看 叫类型缩减更适合一些

两个类型的联合类型有可能会发生类型扩张 例如

type URStr = '123' | string;
// 类型是 string

‘123’ 是 string 类型的子类型 在经过联合之后 联合类型就变成 string 类型了 由于 “123” 类型范围小 string 类型的范围比较大 因此感觉叫类型扩张更合适一些

有了上面两个知识点 我们就可以写成下面的样子 在 ITypeKeyAny 类型中的 age 类型 设置为 never 后 不会和下面的 string 类型冲突 因为 never 类型是任何类型的子类型 在和 ITypeAge 类型联合也不会冲突 并且 age 类型扩张为 number 类型

interface ITypeAge {
	age: number;
};

interface ITypeKeyAny{
	age: never;
	[key: string]: string;
}

type Itype = ITypeAge | ITypeKeyAny;

never 表示永远不会发生的类型 即永远不能有值 比如用抛出错误的函数 用执行无限循环的函数 它们的返回值就是 never 再比如 never【】 表示数组中不会有值

const throwError = (message: string): never => {
	throw new Error(message);
	
};
// const throwError: (message: string) => void
const throwError = (message: string) => {
	if(!message) throw new Error("error");
};

注意:如果一个函数永远都不会有返回值 说明函数调用位置后的代码永远都不会执行

相关文章:

  • vulnhub BTRSys: v2.1
  • mysql使用小记--group_concat()、sum()
  • SpringBoot学习笔记(五)IOC
  • 微信、QQ防撤回
  • RKMPP库快速上手--(三)MPP解码入门
  • torch.nn.interpolate—torch上采样和下采样操作
  • DBCO-PEG-OPSS/OPSS-PEG-DBCO/二苯并环辛炔聚乙二醇修饰邻吡啶二硫
  • SpringCloud与SpringCloudAlibaba的比较
  • PostgreSQL修炼之道笔记之准备篇(四)
  • Springboot整合Redis集群实战详解
  • 聚乙烯亚胺偶联乳清白蛋白/肌白蛋白/豆清白蛋白/蓖麻蛋白/豌豆白蛋白1b ( PA1b)科研试剂
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • springBoot整合SqlSessionTemplate使用
  • jieba—第三方中文分词函数库
  • Python桌面文件清理脚本
  • C++入门教程(10):for 语句
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • emacs初体验
  • JavaScript函数式编程(一)
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • nginx 配置多 域名 + 多 https
  • PHP的类修饰符与访问修饰符
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • SegmentFault 2015 Top Rank
  • 阿里云应用高可用服务公测发布
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 电商搜索引擎的架构设计和性能优化
  • 日剧·日综资源集合(建议收藏)
  • 设计模式走一遍---观察者模式
  • 我这样减少了26.5M Java内存!
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • Java性能优化之JVM GC(垃圾回收机制)
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • #AngularJS#$sce.trustAsResourceUrl
  • $forceUpdate()函数
  • $jQuery 重写Alert样式方法
  • (33)STM32——485实验笔记
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (附源码)springboot教学评价 毕业设计 641310
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (论文阅读30/100)Convolutional Pose Machines
  • (五)MySQL的备份及恢复
  • (一)VirtualBox安装增强功能
  • (转)重识new
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • ..回顾17,展望18
  • .gitignore文件---让git自动忽略指定文件
  • .Net mvc总结
  • .net 微服务 服务保护 自动重试 Polly
  • .NET 中 GetProcess 相关方法的性能
  • .NET是什么