TypeScript学习笔记

来源:https://www.bilibili.com/video/BV1NR4y1x7Ab

TypeScript 的介绍

TypeScript是一种由微软开发的开源、跨平台的编程语言。它是JavaScript的超集,最终会被编译为JavaScript代码。

TypeScript 的特点

  • 始于JavaScript,归于JavaScript

TypeScript 可以编译出纯净、 简洁的 JavaScript 代码,并且可以运行在任何浏览器上、Node.js 环境中和任何支持 ECMAScript 3(或更高版本)的JavaScript 引擎中。

  • 强大的类型系统

类型系统允许 JavaScript 开发者在开发 JavaScript 应用程序时使用高效的开发工具和常用操作比如静态检查和代码重构。

  • 先进的 JavaScript

TypeScript 提供最新的和不断发展的 JavaScript 特性,包括那些来自 2015 年的 ECMAScript 和未来的提案中的特性,比如异步功能和 Decorators,以帮助建立健壮的组件。

安装 TypeScript

npm install -g typescript
tsc -v # 检查是否安装成功

编译TypeScript程序

手动编译

tsc helloworld.ts

VsCode自动编译

  • 生成配置文件tsconfig.json
tsc --init
  • 修改tsconfig.json配置
"outDir": "./js",
"strict": false,
  • 启动监视任务
终端 -> 运行任务 -> 监视tsconfig.json

TypeScript常用语法

基础类型

布尔

let flag: boolean = true;

数字

let num0: number = 10 //十进制
let num1: number = 0b10 //二进制
let num2: number = 0o12 //八进制
let num3: number = 0xa // 十六进制

字符串

可以用单引号或者双引号

let str: string = "haha"

undefined和null

TypeScript 里,undefined 和 null 两者各自有自己的类型分别叫做 undefined 和 null。 它们的本身的类型用处不是很大。

默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和 undefined 赋值给 number 类型的变量。

let u: undefined = undefined
let n: null = null

数组

let list0: number[] = [1, 2, 3]
let list1: Array<number> = [1, 2, 3]

元组

let t: [string, number] = ["hello", 1]

枚举

enum Color {
    Red,
    Green,
    Blue,
} //枚举数值默认从0开始一次递增
let color: Color = Color.Green 

any

当我们不希望类型检查器对某些值进行检查而是直接让它们通过编译阶段的检查时, 可以使用 any 类型来标记这些变量。

let a: any = 4
a = "world"

void

某种程度上来说,void 类型像是与 any 类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void。

声明一个 void 类型的变量没有什么大用,因为你只能为它赋予 undefined 和 null。

function f(): void {
    console.log("f")
}

let v: void = undefined

object

object 表示非原始类型,也就是除 number,string,boolean之外的类型。

联合类型

表示取值可以为多种类型中的一种

function f(x: number | string): string {
    return x.toString()
}

类型断言

通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript 会假设你,程序员,已经进行了必须的检查。

类型断言有两种形式。 其一是“尖括号”语法, 另一个为 as 语法。

function getLength(x: number | string) {
    if ((<string>x).length) {
        return (x as string).length
    } else {
        return x.toString().length
    }
}

类型推断

TS会在没有明确的指定类型的时候推测出一个类型

  • 定义变量时赋值了, 推断为对应的类型
  • 定义变量时没有赋值, 推断为any类型
let a = 123 //number
let b //any
b = 123
b = "hello"

接口

interface IPerson {
    readonly id: number //只读
    name: string //必有
    age: number
    sez?: string //可选
    (source: string, subString: string): boolean //函数
}

class A {
    // 属性
    message: string 
    
    // 构造方法
    constructor (message: string) {
        this.message = message
    }
    
    // 普通方法
    greet(): string{
        return "hello" + this.message
    }
}

const a = new A("world")
console.log(a.greet())

继承

  • 一个类可以实现多个接口,implements
  • 一个接口可以继承多个接口,extends
interface Alarm {
    alert(): any;
}

interafce CarAlarm extends Alarm{
    
}

class Car implements CarAlarm {
    alert() {
        console.log("Car")
    }
}

class Ship extends Car {
    alert() {
        console.log("Ship")
    }
}

修饰符

public

成员都默认为 public。

private

当成员被标记成 private 时,它就不能在声明它的类的外部访问。

protected

protected 修饰符与private修饰符的行为很相似,但有一点不同,protected成员在派生类中仍然可以访问。

readonly

可以使用 readonly 关键字将属性设置为只读的。只读属性必须在声明时或构造函数里被初始化。

参数属性

参数属性可以方便地让我们在一个地方定义并初始化一个成员。

class Person {
    constructor(readonly name: string){
        
    }
}
const p = new Person("jack")
console.log(p.name)

参数属性通过给构造函数参数前面添加一个访问限定符来声明。使用 private 限定一个参数属性会声明并初始化一个私有成员;对于 public 和 protected 来说也是一样。

存取器

class Person{
    firstName: string = "A"
    lastName: string = "B"
    get fullName() {
        return this.firstName + "_" + this.lastName
    }
    set fullName(value) {
        const names = value.split("_")
        this.firstName = names[0]
        this.lastName = names[1]
    }
}

const p = new Person()
console.log(p.fullName)
p.fullName = "C_D"

静态属性

静态属性时类对象的属性,而非静态属性,是类的实例对象的属性

class Person{
    name1: string = "A"
    static name2: string = "B"
}
console.log(Person.name2)
console.log(new Person().name1)

抽象类

抽象类做为其它派生类的基类使用。它们不能被实例化。不同于接口,抽象类可以包含成员的实现细节。

abstract class Animal{
    abstract cry()
    
    run() {
        console.log("run")
    }
}

class Dog extends Animal {
    cry() {
        console.log("dog cry")
    }
}

const dog = new Dog()
dog.cry()
dog.run()

函数

//命名函数
function add(x number, y number): number {
    return x + y
}

//匿名函数
let add2 = function(x number, y number): number{
    return x + y
}

//函数类型
let add3: (x: number, y: number) => number = 
function(x: number, y: number): number {
    return x + y
}

可选参数和默认参数

在TypeScript 里我们可以在参数名旁使用 ? 实现可选参数的功能。
也可以为参数提供一个默认值当用户没有传递这个参数或传递的值是 undefined 时,使用该默认值。

function buildName(firstName: string='A', lastName?: string): string {
    if (lastName) {
        return firstName + '-' + lastName
    } else {
        return firstName
    }
}

剩余参数

可以把所有参数收集到一个变量里:剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 编译器创建参数数组,名字是你在省略号( ...)后面给定的名字,你可以在函数体内使用这个数组。

function info(x: string, ...args: string[]) {
    console.log(x, args)
}

函数重载

数名相同, 而形参不同的多个函数

在JS中, 由于弱类型的特点和形参与实参可以不匹配, 是没有函数重载这一说的 但在TS中, 与其它面向对象的语言(如Java)就存在此语法。

// 重载函数声明
function add (x: string, y: string): string
function add (x: number, y: number): number

// 定义函数实现
function add(x: string | number, y: string | number): string | number {
    // 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 x + y
    if (typeof x === 'string' && typeof y === 'string') {
        return x + y
    } else if (typeof x === 'number' && typeof y === 'number') {
        return x + y
    }
}

这并不是真正意义上的函数重载。

泛型

指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定具体类型的一种特性。

泛型函数

function swap <K, V> (a: K, b: V): [K, V] {
    return [a, b]
}
const result = swap<string, number>('abc', 123)

泛型接口

interface IbaseCRUD <T> {
    data: T[]
    add: (t: T) => void
}

class User {
    id?: number; 
    name: string; 
    age: number; 

    constructor (name, age) {
        this.name = name
        this.age = age
    }
}

class UserCRUD implements IbaseCRUD <User> {
    data: User[] = []
  
    add(user: User): void {
        user = {...user, id: Date.now()}
        this.data.push(user)
    }

    getById(id: number): User {
        return this.data.find(item => item.id===id)
    }
}

泛型类

在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型

class GenericNumber<T> {
  zeroValue: T
  add: (x: T, y: T) => T
}

let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 0
myGenericNumber.add = function(x, y) {
    return x + y 
}

泛型约束

interface Lengthwise {
    length: number;
}

// 指定泛型约束
function fn2 <T extends Lengthwise>(x: T): void {
    console.log(x.length)
}

声明文件

当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。

假如我们想使用第三方库 jQuery,一种常见的方式是在 html 中通过 <script> 标签引入 jQuery,然后就可以使用全局变量 $ 或 jQuery 了。

但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么东西。这时,我们需要使用 declare var 来定义它的类型

declare var jQuery: (selector: string) => any;

jQuery('#foo');

一般声明文件都会单独写成一个 xxx.d.ts 文件很多的第三方库都定义了对应的声明文件库, 库文件名一般为 @types/xxx。有的第三库在下载时就会自动下载对应的声明文件库(比如: webpack),有的可能需要单独下载(比如jQuery/react)

//下载jquery的声明文件
npm install @types/jquery --save-dev

内置对象

JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。

内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准。

  • ECMAScript 的内置对象

Boolean
Number
String
Date
RegExp
Error

  • BOM 和 DOM 的内置对象

Window
Document
HTMLElement
DocumentFragment
Event
NodeList

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容