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

总结

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

  • 数组类型可用泛型、接口等方式约束
  • 函数的可选参数、默认参数、剩余参数,函数重载
  • 联合类型、类、接口、双重断言
  • 常见的内置对象
相关文章
|
3月前
TS 快速入门
TS 快速入门
14 0
|
3月前
ts笔记
ts笔记
|
3月前
|
JavaScript
使用TS的一些基础知识
使用TS的一些基础知识
43 0
|
3月前
|
JavaScript 前端开发 编译器
ts面试题总结
ts面试题总结
91 0
|
9月前
|
JavaScript 前端开发 开发者
ts知识点
ts知识点
45 0
|
11月前
|
JavaScript 安全 Python
TS笔记
TS笔记
51 0
|
10月前
|
JavaScript 前端开发 Java
对TS的重新学习(一)
对TS的重新学习(一)
33 0
|
10月前
|
JavaScript 前端开发 开发工具
CocosCreator 面试题(五)TS有什么优缺点?为什么要用TS?
CocosCreator 面试题(五)TS有什么优缺点?为什么要用TS?
136 0
|
JavaScript 前端开发 IDE
TS知识点
TS知识点
|
存储 JavaScript 前端开发
ts面试总结题
ts面试总结题
67 0