Typescript笔记
馨er BOSS

TypeScript笔记

1 认识TypeScript

TypeScript的出现是为了解决JavaScript不进行类型检测的问题

TypeScript是拥有类型的JavaScript超集,它可以编译成普通、干净、完整的JavaScript代码。

TypeScript是JavaScript的一个超集

TypeScript编译环境

npm install typescript -g

tsc --version

tsc index.ts 将.ts文件编译为.js文件

tsc --watch index.ts 使用tsc命令的监视模式,只要重新保存了ts文件,就会自动调用tsc将ts文件转换为js文件

TypeScript运行环境 node.js

npm install ts-node -g

npm install tslib @types/node -g

ts-node index.ts 直接通过ts-node运行.ts文件

注释有单行注释和多行注释;分号同JS,可写可不写

2 数据类型

13种类型,分为原始类型(基本数据类型)和对象类型(复杂数据类型)。常见的基本数据类型有5个。number、string、boolean、undefined、null

2.1 number

不区分整型和浮点型,支持二进制,八进制,十进制,十六进制

1
2
3
4
num = 100;  // 十进制
num = 0b110; // 二进制
num = 0o555; // 八进制
num = 0xf23; // 十六进制

2.2 boolean

只有两个值:true和false

1
2
3
let flag: boolean = true;
flag = false;
flag = 20 > 30;

2.3 string

推荐写单引号,而非双引号。加号两边只要有一边是字符串,就执行字符串拼接;除加号外,其他算术运算符只应该跟数字类型一起使用。在字符串前面添加+号,可以将string转化为number类型

1
2
3
4
5
6
7
8
9
let message: string = "hello world";
message = 'Hello TypeScript';
console.log('周杰'+'伦') // 周杰伦
console.log(1+'2') // 12
console.log('1'+2) // 12
console.log(2-'1') // 报错:算术运算符的右侧必须是数字类型
// 上述代码可以改为
console.log(2-+'1') // 结果为1
// +'1'表示将'1'(string)=>1(number)

支持ES6的模板字符串来拼接变量和字符串:

1
2
3
4
5
6
const name = "why";
const age = 18;
const height = 1.88;

const info = `my name is ${name}, age is ${age}, height is ${height}`;
console.log(info);

2.4 Array类型

两种形式:

1
2
3
4
5
const names: string[] = ["abc", "cba", "cba"];
const names2: Array<string> = ["abc", "cba", "nba"];

names.push("why");
names2.push("why");

如果添加其他类型到数组中将会报错

2.5 object

object对象类型可以用于描述一个对象:

1
2
3
4
5
const myInfo: object = {
name: "why",
age: 18,
height: 1.88
}

但是从myinfo中我们不能获取数据,也不能设置数据

2.6 Symbol

在ES5中,如果我们是不可以在对象中添加相同的属性名称的。通常我们的做法是定义两个不同的属性名字:比如identity1和identity2。

但是我们也可以通过symbol来定义相同的名称,因为Symbol函数返回的是不同的值:

1
2
3
4
5
6
7
const s1: symbol = Symbol("title");
const s2: symbol = Symbol("title");

const person = {
[s1]: "程序员",
[s2]: "老师"
}

2.7 null和undefined

共同特点:只有一个值,值为类型本身

1
2
let n: null = null;
let u: undefined = undefined;

undefined和null的区别:

  • undefined:表示声明但未赋值的变量值(找不到值)
  • null:表示声明了变量并已赋值,值为null(能找到,值就是null)

2.8 any

在某些情况下,我们确实无法确定一个变量的类型,并且可能它会发生一些变化,这个时候我们可以使用any类型

any类型有点像一种讨巧的TypeScript手段:

  • 我们可以对any类型的变量进行任何的操作,包括获取不存在的属性、方法;

  • 我们给一个any类型的变量赋值任何的值,比如数字、字符串的值;

1
2
3
4
5
let a: any = "why";
a = 123;
a = true;

const aArray: any[] = ["why", 18, 1.88];

如果对于某些情况的处理过于繁琐不希望添加规定的类型注解,或者在引入一些第三方库时,缺失了类型注解,这个时候我们可以使用any: 包括在Vue源码中,也会使用到any来进行某些类型的适配;

2.9 unknown

描述类型不确定的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function foo(): string {
return 'foo'
}
function bar(): number {
return 123
}
const flag = true
let result: unknown

if (flag) {
result = foo()
} else {
result = bar()
}
if (typeof result === 'string') {
console.log(result.length);
}

2.10 void

通常用来指定一个函数是没有返回值的,那么它的返回值就是void类型。我们可以将null和undefined赋值给void类型,也就是函数可以返回null或者undefined

2.11 never

表示永远不会发生值的类型,比如一个函数:

  • 如果一个函数中是一个死循环或者抛出一个异常,那么这个函数会返回东西吗?
  • 不会,那么写void类型或者其他类型作为返回值类型都不合适,我们就可以使用never类型;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function loopFun(): never {
while (true) {
console.log("123");
}
}
function loopErr(): never {
throw new Error()
}
function handleMessage(message: number|string) {
switch (typeof message) {
case "string":
console.log('foo');
break
case 'number':
console.log('bar');
break
default:
const check: never = message
}
}

2.12 tuple

元组类型

1
2
3
const tInfo: [string, number, number] = ["why", 18, 1.88];
const item1 = tInfo[0]; // why,并且知道类型是string类型
const item2 = tInfo[1]; // 18,并且知道类型是number类型

tuple和数组的区别:

  • 首先,数组中通常建议存放相同类型的元素,不同类型的元素是不推荐放在数组中。(可以放在对象或者元组中)
  • 其次,元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型;
1
2
3
4
const info: (string|number)[] = ["why", 18, 1.88]
const item1 = info[0]; // 不确定类型
const tInfo: [String, number, number] = ["why", 18, 1.88]
const item2 = tInfo[0]; // 一定是string类型

应用场景:通常可以作为返回的值

1
2
3
4
5
6
7
8
function useState<T>(state: T): [T, (newState: T) => void] {
let currentState = state
const changeState = (newState: T) => {
currentState = newState
}
return [currentState, changeState]
}
const [counter, setCouter] = useState(10)

3 数组

3.1 基本使用

第一种方式

1
let names:string[] = ['sjx', 'sjk', 'syf']

第二种方式(不推荐)

1
let names:string[] = new Array('sjx', 'sjk', 'syf')

功能与[]相同,但是更加繁琐

3.2 数组长度和索引

数组长度

数组长度:表示数组中元素的个数,通过数组的length属性来获取

数组索引

从0开始,最大索引=数组长度-1

3.3 往数组的后面添加新值

1
newArr[newArr.length] = 1;

4 函数

typescript允许我们指定函数的参数和返回值的类型

4.1 函数的参数类型

声明函数时,可以在每个参数后添加类型注解,以声明函数接受的参数类型

4.2 函数的返回值类型

和变量的类型注解一样,我们通常情况下不需要返回类型注解,因为TypeScript会根据 return 返回值推断函数的返回类型

4.3 匿名函数的参数

匿名函数与函数声明会有一些不同:

  • 当一个函数出现在TypeScript可以确定该函数会被如何调用的地方时;

  • 该函数的参数会自动指定类型;

1
2
3
4
const names = ["abc", "cba", "nba"];
names.forEach(item => {
console.log(item.toUpperCase());
})

我们并没有指定item的类型,但是item是一个string类型:

  • 这是因为TypeScript会根据forEach函数的类型以及数组的类型推断出item的类型;

  • 这个过程称之为上下文类型(contextual typing),因为函数执行的上下文可以帮助确定参数和返回值的类型;

4.4 对象类型

对象类型做函数参数

函数接受的参数是一个对象,属性之间可以使用;来分割;每个属性的类型部分也是可选的,如果不指定,那么就是any类型

1
2
3
4
5
6
function printCoordinate(point: {x: number, y: number}) {
console.log("x坐标:", point.x)
console.log("y坐标:", point.y)
}

printCoordinate({x: 10, y: 30})

可选类型

对象类型也可以指定哪些属性是可选的,可以在属性的后面添加一个?:

1
2
3
4
5
6
7
8
9
10
function printCoordinate(point: {x: number, y: number, z?: number}) {
console.log("x坐标:", point.x)
console.log("y坐标:", point.y)
if (point.z) {
console.log("z坐标:", point.z)
}
}

printCoordinate({x: 10, y: 30})
printCoordinate({x: 10, y: 30, z: 40})

可选类型可以看作是类型和undefined的联合类型

1
2
3
4
5
6
7
8
9
10
function print(message?: string) {
console.log(message)
}

print()
print("coderwhy")
print(undefined)

// error
print(null)

4.5 联合类型

TypeScript的类型系统允许我们使用多种运算符,从现有类型中构建新类型

第一种组合类型的方法——联合类型

  • 联合类型是由两个或者多个其他类型组成的类型
  • 表示可以是这些类型中的任何一个值
  • 联合类型中的每一个类型被称之为联合成员
1
2
3
4
5
6
function printId(id: number|string) {
console.log("你的id是:", id)
}

printId(10)
printId("abc")

一般情况下需要缩小联合

1
2
3
4
5
6
7
8
9
10
11
12
function printId(id: number|string) {
if (typeof id === 'string') {
// 确定id是string类型
console.log("你的id是:", id.toUpperCase())
} else {
// 确定id是number类型
console.log("你的id是", id)
}
}

printId(10)
printId("abc")

4.6 类型别名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Point = {
x: number
y: number
}

function printPoint(point: Point) {
console.log(point.x, point.y)
}

function sumPoint(point: Point) {
console.log(point.x + point.y)
}

printPoint({x: 20, y: 30})
sumPoint({x: 20, y: 30})
1
2
3
4
type ID = number|string
function printId(od: ID) {
console.log("您的id:", id)
}

5 对象

5.1 对象概述

一组相关属性和方法的集合,并且是无序的

5.2 接口

对象的类型注解

语法说明

1
2
3
4
let person: {
name: string;
age: number;
}

与对象的区别:键值对中的值是类型(这是对象的类型注解);多个键值对之间使用分号分隔,并且分号可省略;接口的名字后面为冒号而非赋值。类型注解后,定义对象时不需要写let,防止变量的重复声明

对象方法的类型注解

参数,返回值

1
2
3
4
let p1: {
sing: (name: string) => void;
sum: (num1: number, num2: number) => number;
}

接口的使用

直接在对象名称后面写类型注解的坏处:代码结构不间接;无法复用类型注解

接口:为对象的类型注解命名,并为你的代码建立契约来约束对象的结构。interface表示接口,接口名称约定以I开头,推荐使用接口来作为对象的类型注解

1
2
3
4
5
6
7
8
interface IUser {
name: string
age: number
}
let p1:IUser = {
name: 'jack',
age: 18
}

5.3 内置对象

数组对象

属性:length

方法:push、forEach(遍历数组)、some(遍历数组,查找是否有一个满足条件的元素(如果有,就可以停止循环))

1
2
3
4
let songs: string[] = ['五环之歌', '探清水河', '晴天']
songs.forEach(function (item, index) {
console.log('索引为', index, '元素为', item)
})

上面的例子中forEach方法的参数是一个函数,这种函数也称为回调函数。forEach方法的执行过程:遍历整个数组,为数组的每一项元素,调用一次回调函数

1
2
3
4
5
6
7
8
9
let has: boolean = nums.some(function(num)) {
if(num > 10){
// 说明找到满足条件的元素,通过返回true来停止后续循环
return true
}
// 说明没有找到满足条件的元素,通过返回false来继续后面的循环
return false
}
console.log(has)

在typescript中,定义变量时可以不指定类型

情况一:

1
2
let num = 1
num = '' // 代码会报错,第一行代码发生了类型推论

情况二:

1
2
3
let num
num = 1
num = '' // 不发生类型推论,不会报错

推荐书写typescript代码时,能省略类型注解的地方就省略,充分利用TS类型推论的能力,提升开发效率

  • 本文标题:Typescript笔记
  • 本文作者:馨er
  • 创建时间:2022-05-01 21:18:03
  • 本文链接:https://sjxbbd.vercel.app/2022/05/01/25b99359dc7b/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!