ts:从入门到放弃(二)

简介: 温故而知新,回顾前文学到的数据类型:boolean、number、string、void、null、undefined、any,然后是类型:联合类型、接口类型,本文继续来学习TypeScript,相信我会越学越上头。

温故而知新,回顾前文学到的数据类型:boolean、number、string、void、null、undefined、any,然后是类型:联合类型、接口类型,本文继续来学习TypeScript,相信我会越学越上头。

基础

数组

数组的类型表示比较灵活

类型声明

直接使用类型[]的方式来约束数组的类型,数组中的数据必须满足类型约束。类型可以是单个类型,也可是联合类型

let isNumberArr: number[] = [1,2,3];
// let isNumberArr: number[] = [1,2,'3']; // 数组中必须满足类型约束,不允许出现其他类型的数据
// let isNumberArr: (number | string)[] = [1,2,'3']; // 联合类型

使用泛型

我们也可以使用数组泛型来约束类型

let isArr: Array<number> = [1,2,3];
// let isArr: Array<number | string> = [1,2,'3'];

使用接口

接口可用来表示一种类型,数组也可以使用。采用接口的方式可以其他地方使用

interface NumberArray {
  [index: number]: number
}
let isNumArr:NumberArray = [1,2,3];

类数组

类数组,不是普通的数组,只是类似数组。一般来说,类数组会采用接口的方式定义。

interface IArgument {
  [index: number]: string,
  length: number,
  callee: Function,
}
function sum(x:number, y:number) {
  let args:IArgument = arguments
  console.log(arguments, args[0]);
}
sum(1, 2)

细心的朋友可能会发现,接口中好像有一个任意属性,其实不是的。任意属性的key只能是字符串类型,本处是number类型,更像是数组的索引。这就是类数组,看起来像,但又不完全是。

函数

JavaScript中,函数可算得上是“亲儿子”,重要地位非同一般。定义函数一般有两种方式:function声明、表达式定义。如果需要使用ts对函数进行约束,那么其输入和输出都应该考虑到。

function sum1(x: number, y: number): number {
  return x + y;
} // function
let sum2 = (x: number, y: number): number => {
  return x + y;
} // 表达式

也可以使用接口来定义函数的形式。

interface SumFuc {
  (x: number, y: number): number;
}
let sum3: SumFuc = function(x: number, y: number) {
  return x + y;
}

可选参数

类似于对象的可选属性,使用?来声明,值得注意的是可选参数后面不能再出现必需参数,并且可选参数在必需参数后面。

function sum4(x: number, y: number, z?: number): number {
  if (z) {
    return x + y + z;
  }
  return x + y;
}

默认参数

可以给函数的参数添加默认值,ts会将添加了默认值的参数识别为可选参数,此时默认参数并没有位置要求,其后也可以跟必需参数。

function sum5(x: number = 10, y: number, z?: number): number {
  if (z) {
    return x + y + z;
  }
  return x + y;
}

剩余参数

有时候参数很多,或者不确定有哪些参数,可以采用剩余参数的方式将这些参数都放在一个参数列表中。

function sum6(x: number, ...items: number[]): number {
  items.forEach(element => {
    x+= element
  });
  return x;
}
console.log(sum6(1,2,3,4,5)); // 15

函数重载

如果一个函数接收不同的参数类型和参数数量,并作出不同的响应处理,那么这个函数就是重载函数,关键点在于不同的参数列表。例如我们想实现字符串数值、数字两者之间任意组合的相加。

function add(x: number, y:number):number;
function add(x:number, y:string): number;
function add(x:string, y:number): number;
function add(x:string, y:string): number;
function add(x: number | string, y: number | string): number {
  if (isNaN(Number(x)) || isNaN(Number(y))) {
    return 0;
  }
  return Number(x) + Number(y);
}
console.log('add', add('1', 2));

类型断言

类型断言就是手动指定一个值的类型,一般用于可能会有多种类型的选择的时候。使用方式:值 as 类型,或者<类型>值。为了考虑兼容性,建议使用as来做类型断言。

联合类型中使用类型断言

function fun1(x: string | number): void {
  console.log((x as string).split('').reverse().join());
}

使用类型断言需要注意:类型断言只能解决编译时的报错,但是无法避免运行时的报错。合理使用断言,避免断言后调用方法或者深层次引用属性,减少不必要的运行时错误。

将一个父类断言为更加具体的子类

当类之间存在继承关系时,可以使用类型断言。

class AError extends Error {
  code: number = 999
}
class BError extends Error {
  status: number = 200
}
// function isAError(error: Error) {
//   if (error instanceof AError) {
//     return true;
//   }
//   return false;
// } // 更推荐
function isAError(error: Error) {
  if (typeof (error as AError).code === 'number') {
    return true;
  }
  return false;
}

当接口之间存在继承关系,也可以使用类型断言

interface AError extends Error {
  code: number;
}
interface BError extends Error {
  status: number;
}
function isAError2(error: Error) {
  if (typeof (error as AError).code === 'number') {
    return true;
  }
  return false;
}

将任何一个类型断言为any

any表示任意类型,一旦某个值的类型被断言为any,那么将可以访问任何属性和方法。尽管如此,若非必要,不建议将类型断言为any。

(window as any).foo = 1;

将任意类型any断言为一个具体的类型

function getCacheData(key: string): any {
  return (window as any).cache[key];
}
interface Cat {
  name: string;
  run(): void;
}
const tom = getCacheData('tom') as Cat;
tom.run();

双重断言

既然任意类型可以被断言为any,然后any也可以被断言为任意类型,那么两个不兼容的类型就可以通过双重断言来实现。

interface Cat {
  run(): void;
}
interface Fish {
  swim(): void;
}
function testCat(cat: Cat) {
  return (cat as any as Fish).swim();
} // 双重断言很容易出现运行时错误,若非必要,不建议使用双重断言

类型断言的限制

类型断言不是说任意类型都可以被断言为其他任意类型的,只有兼容的两个类型之间才可以断言。例如A兼容B,那么A就能被断言为B,同样B也能被断言为A;B兼容A,那么A就能被断言为B,同样B也能被断言为A。说起来有点绕,那么怎么理解兼容呢?

对于联合类型来说,肯定是兼容对应的单一类型的,因此联合类型可以被断言为其中的一种类型;ts是结构类型系统,类型之间的对比只会对比其最终的解构,会忽略他们定义时的关系。如果是类或接口之间存在继承关系,这种继承关系可以是显示的extends,也可以是隐式的(拥有相同属性或方法),那么此时父类是兼容子类的,也就可以断言。

interface Animal {
  name: string;
}
interface Cat {
  name: string;
  run(): void;
}
// 等价于
interface Animal {
  name: string;
}
interface Cat extends Animal {
  run(): void;
}
// 那么Animal就兼容Cat,两者就可以进行类型断言

区别

类型断言与类型转换的区别

类型断言只会影响ts编译时的类型,不会实际改变变量的类型,类型断言语句在编译结果中会被删除。而类型转换会实际改变变量类型。

function toBoolean(s: any): boolean {
  return s as boolean; // 原值返回
  // return Boolean(s); // 返回bool值
}
toBoolean(1)

类型断言与类型声明的区别

我们可以在声明变量时就指定其类型,也可以在声明变量后将其类型断言为某一类型,声明和断言很相似,但是还是存在一些差别。A是否能断言为B,只需要满足A兼容B,或者B兼容A。但是如果想把A赋值给B,那么需要满足B兼容A,也就是说A应该是B的子类,不能把父类的实例直接赋值给子类。

类型声明比类型断言更加严格,应该优先使用类型声明。

interface Animal {
  name: string;
}
interface Cat {
  name: string;
  run(): void;
}
const animal: Animal = {
  name: 'tom',
  eat: function (): void {
    throw new Error("Function not implemented.");
  }
};
// let cat: Cat = animal; // 编译出错
let cat = animal as Cat; // 断言,编译正常

类型断言和泛型的区别

我们可以把函数改造为泛型,在实际调用时指定具体的类型,这样不经可以时间断言一样的效果,而且还可以避免出现any。

function getCache<T>(key: string): T {
  return (window as any).cache[key]
}
interface Cat {
  name: string,
  run(): void
}
let catData = getCache<Cat>('tom');

内置对象

js中有很多的内置对象,也可以直接在ts中使用。

  • ES内置对象,例如Boolean、Date、RegExp等

    let bool: Boolean = new Boolean(1); // true
    let date:Date = new Date();
    let regexp: RegExp = /[ab]/
  • DOM和BOM的内置对象,例如Document、HTMLElement、Event等

    let div:HTMLDivElement = document.getElementsByTagName('div')[0]

TypeScript和Node.js

Node.js不是内置对象的一部分,如果要用ts写Node.js,则需要引入Node.js的声明文件。

npm install @types/node --save-dev

总结

今天的摸鱼时间结束,总结一下今天学到的内容:

  • 数组类型可用泛型、接口等方式约束
  • 函数的可选参数、默认参数、剩余参数,函数重载
  • 联合类型、类、接口、双重断言
  • 常见的内置对象
相关文章
|
11月前
|
机器学习/深度学习 人工智能 搜索推荐
拔俗AI学伴智能体系统:基于大模型与智能体架构的下一代个性化学习引擎
AI学伴智能体系统融合大模型、多模态理解与自主决策,打造具备思考能力的个性化学习伙伴。通过动态推理、长期记忆、任务规划与教学逻辑优化,实现千人千面的自适应教育,助力因材施教落地,推动教育公平与效率双提升。(238字)
1278 0
|
Ubuntu Linux C语言
【操作系统原理】—— 信号量与PV操作实现
【操作系统原理】—— 信号量与PV操作实现
1459 0
|
缓存 关系型数据库 MySQL
MySQL EXPLAIN详解
MySQL数据库是许多Web应用程序的底层支持,而查询性能的优化是确保系统高效运行的关键。在MySQL中,`EXPLAIN`是一项强大的工具,可帮助开发者深入了解查询语句的执行计划,从而更好地优化查询性能。本文将详细解析MySQL的`EXPLAIN`关键字,以揭开查询执行计划的面纱。
621 1
MySQL EXPLAIN详解
|
Apache
Apache域名跳转----配置rewrite模块
Apache域名跳转----配置rewrite模块
707 0
|
应用服务中间件 nginx Android开发
Nginx如何处理手机端和PC端跳转不同页面
如果是手机端和pc端需要跳转不同的页面, 则需要在nginx.conf中的location / {}中加入如下代码: if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') { rewrite ^.
|
JSON 数据格式 JavaScript
浅谈 JSON.stringify 方法
原文:浅谈 JSON.stringify 方法 一、前言 最近项目中,遇到需要将对象转换成字符串进行传递,上次写过一篇文章关于json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值。
2123 0
|
iOS开发
iOS开发UI篇—Quartz2D使用(图形上下文栈)
iOS开发UI篇—Quartz2D使用(图形上下文栈) 一、qurza2d是怎么将绘图信息和绘图的属性绘制到图形上下文中去的? 说明: 新建一个项目,自定义一个view类和storyboard关联后,重写该类中的drowrect方法。
893 0
|
6天前
|
人工智能 运维 BI
阿里云千问办公QwenWork深度解析:基于Qwen3.8,六大核心能力重构企业全自动化工作流与计费选型指南
传统AI办公工具大多停留在对话问答、文档摘要、简单文案生成层面,只能完成单点碎片化任务,无法自主拆解复杂业务流程,很难串联多工具、多文档、外部业务系统完成端到端完整工作交付。很多企业在落地AI办公的时候,需要组合多款不同工具,来回切换界面,手动复制粘贴中间结果,智能化改造落地门槛居高不下。千问办公QwenWork是整合多款智能体产品能力打造的一体化企业办公智能体平台,底层基座依托Qwen3.8大模型,打通桌面端Agent、云端Agent、企业协同Agent三种运行形态,不再局限简单问答,接收业务目标之后自主拆解任务步骤,调用各类工具,处理文档、表格、浏览器自动化、数据查询,直接输出可交付的办公
1528 0
|
6天前
|
人工智能 自然语言处理 安全
阿里云AI数智鉴密:AI 生成内容如何拿到一张"防篡改的身份证"
隐形水印 + C2PA签名:让AI生成内容“持证上岗”。
1136 0
|
15天前
|
人工智能 自然语言处理 安全
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考
本文聚焦阿里云2026年推出的三款自研AI办公产品,清晰拆解千问办公、Qoder Teams、Qoder CN的差异化定位与能力边界:千问办公主打职场全场景提效,支持自然语言指令一键完成PPT生成、数据分析等高频办公任务;Qoder Teams面向程序员团队,深度整合AI代码生成、团队协同与企业知识库能力;Qoder CN则专为金融、政务等强合规场景打造,实现数据不出境与VPC私有化部署。文章同步给出分场景选型指南与最新活动定价,帮助不同类型的企业按需组合产品,实现业务岗、研发岗与强合规场景的AI能力全覆盖。
3806 4
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考