安装

安装 typescript 编译器

> npm i -g typescript

安装 ts-node 和 ts-lib,使用 ts-node 可以直接运行 ts 文件,期间也不会产生 js 文件

> npm i -g ts-node
> npm i -g tslib @types/node

Hello World

新建一个 hello.ts 文件,内容如下

console.log("hello ts");

使用 tsc 命令编译生成 hello.js 文件。

> tsc hello.ts

运行 js 文件

> node hello.js

类型

基本的

使用 js 的已有类型:number,string,boolean,null,undefined,symbol

let grade: number = 18
let username: string = '张三'
let graduated: boolean = false
let classes: null = null
let couple: undefined = undefined
let s: symbol = Symbol()

联合类型

该变量可以有多种类型,比如下面的 date 变量既可以是 string 又可以是 null 类型。

let date: string | null = null
date = '2022-12-23'

对象类型

数组

定义一个数组

// 数组
let numbers: number[] = [1, 2, 3]
let string: Array<string> = ['1', '2', '3']
let bs: boolean[] = [true, false, false, true]
let bs2: Array<boolean> = [false, true, true, false]

// 自定义类型(类型别名)
type CustomArray = (number | string)[]
let arr1: CustomArray = [1, 2, 3, 'a']

数组中存放两种不同的类型

let numbers2: (number | string)[] = [1, '2', 3, 5, 6, '7', '8']

一定要加上括号,不然就是两种意思了

let var2: number | string[] = 1
var2 = ['12', '22']

元组

元组类型是另一种类型的数组,它确切地知道包含多少个元素,以及特定索引对应的类型。

let position2: [number, number] = [111.234, 231.333]

字面量类型

下面的 ‘Hello TS’,就是一个字面量类型。也就是说某个特定的字符串也可以作为 TS 中的类型。除字符串外,任意的 JS 字面量(比如,对象、数字等)都可以作为类型使用。

let str2: 'Hello TS' = 'Hello TS'

使用模式:字面量类型配合联合类型一起使用。

使用场景:用来表示一组明确的可选值列表。

比如,在贪吃蛇游戏中,游戏的方向的可选值只能是上、下、左、右中的任意一个。

let direction: 'up' | 'right' | 'down' | 'left' = 'up'
direct = 'right'

枚举类型

枚举定义,默认有值,从 0 自增。

enum Direction { Up , Down , Left, Right } // Up=0, Down=1, Left=2, Right=3

可以给枚举初始化值。

enum Direction { Up = 10, Down = 12, Left, Right } // Left=13, Right=14

当赋值为字符串时,字符串没有自增的能力,因此必须为每个元素都赋值。

enum Direction { Up = 'up', Down = 'down', Left = 'left', Right = 'right' }

any 类型

any 类型代表任意类型。非常容易在写代码出现问题,慎用。

let a: any = 1
a = 'a'
a = { name: 'xiaoqiang', age: 15 }
a = () => 'ok'

在函数中的参数,若不指定参数类型,ts 将其认为是 any 类型,其返回值也会认为是 any 类型

image-20221124174836277

自定义类型

自定义类型使用 type 关键字

type direction = 'up' | 'right' | 'down' | 'left' = 'up'

函数

像函数中指定类型和返回值。

function changeDirection(direction: direction): void {
    console.log(direction);
}

某些参数有时可不用传,可以加个“?”标记为可选参数,但是必选参数一定要在前面!

function slice(start: number, end?: number): void { 
    // slice todo
}

两数相加

function add(num1: number, num2: number): number {
    return num1 + num2
}

箭头函数

箭头形式的函数有两种形式,下面是第一种,它是由 A 变成 B。

let add2 = (num1, num2) => num1 + num2 // A
let add2 = (num1: number, num2: number): number => num1 + num2 // B

第二种形式,指定一个“函数类型”并且指定“返回值类型”,这个自己感觉写法上麻烦很多。

const add3: (num1: number, num2: number) => number = (num1, num2) => {
    return num1 + num2
}

接口

描述对象的结构,每一个定义不用逗号或分号结束,且只能为对象指定类型。

interface IPerson {
    name: string
    age: number
    sayhi: () => void
}

const person3: IPerson = {
    name: 'jack',
    age: 19,
    sayhi() {},
}

const person4: IPerson = {
    name: "xiaoqiang",
    age: 0,
    sayhi() {}
}

可选属性

可选属性和函数的参数一样,加个“?”即可。

interface IPerson {
    name: string
    age: number
    sayhi?: () => void
}

const person2: IPerson = {
    name: 'jack',
    age: 19,
    greet(string) {}
}

接口继承

继承使用 extends 关键字。

interface Point2D {
    x: number
    y: number
}

interface Point3D extends Point2D {
    z: number
}

类型推断和断言

推断

多次给属性定义类型或许很麻烦,但是 ts 会做一个类型推断,这样一来就完全没有必要去指定变量的类型了。但是类型推断的前提是该类型必须要赋值。

下图声明了一个 age5 的变量,值为 18。ts 将其判定为 number 类型。

image-20221124171911530

尝试赋值一个字符串,但是报错了“不能将 string 分配给 number 型”,说明 typescript 很智能的。

image-20221124172220662

在某些情况下,函数的返回值也可以被推断出来,比如两数相加,返回值类型为 number 类型。

image-20221124174633745

若只声明却不赋值,会隐式的变成 any 类型,类型推断失效了。此时只能去手动指定其类型。

image-20221124172931575

断言

当我们确切的知道我们想要的类型的时候,此时我们可以使用 as 关键字或者使用 <> 来加入需要的类型。

比如我想通过 ts 获取 a 标签中的 href 属性,获取的代码如下。

const aLink = document.getElementById("link")

但是此时是如何也获取不到 href 属性,通过百度发现 href 属性在 HTMLAnchorElement 中。此时可以这样的两种写法。 as 和 <>

// as
const aLink = document.getElementById("link") as HTMLAnchorElement
console.log(aLink.href)

// <>
const aLink2 = <HTMLAnchorElement>document.getElementById('link')
console.log(aLink2.href)