TypeScript——基础语法

认识TypeScript

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

TypeScript的编译环境

        TypeScript最终会被编译成JavaScript来运行,所以我们需要搭建对应的环境。我们需要在电脑上安装TypeScript,这样就可以通过TypeScript的Compiler将其编译成JavaScript。

# 安装命令
npm install typescript -g
# 查看版本
tsc --version
# 编译TS文件
tsc ./index.ts

TypeScript的运行环境

  1. 通过tsc编译TypeScript到JavaScript代码,在浏览器或者Node环境下运行JavaScript代码;
  2. 通过webpack,配置本地的TypeScript编译环境和开启一个本地服务,可以直接运行在浏览器上;
  3. 通过ts-node库,为TypeScript的运行提供执行环境;

 使用ts-node

# 安装ts-node
npm install ts-node -g
# 另外ts-node需要依赖 tslib 和 @types/node 两个包
npm install tslib @types/node -g
# 通过 ts-node 来运行TypeScript的代码
ts-node index.ts

tip:安装ts-node后,可以使用nodemon直接运行TS文件。

变量的声明

        声明了类型后TypeScript就会进行类型检测,声明的类型可以称之为类型注解(Type Annotation)。完整的声明格式如下:var/let/const 标识符: 数据类型 = 赋值;

JavaScript和TypeScript的数据类型

JavaScript类型 – number类型

         数字类型是我们开发中经常使用的类型,TypeScript和JavaScript一样,不区分整数类型(int)和浮点型(double),统一为 number类型。

        ES6新增了二进制和八进制的表示方法,而TypeScript也是支持二进制、八进制、十六进制的表示:

let num: number
num = 100 // 十进制
num = 0b110 // 二进制
num = 0o555 // 八进制
num = 0xf23 // 十六进制
JavaScript类型 – boolean类型

        boolean类型只有两个取值:true和false。

JavaScript类型 – string类型

        string类型是字符串类型,可以使用单引号或者双引号表示,同时也支持ES6的模板字符串来拼接变量和字符串。

JavaScript类型 – Array类型
const list: string[] = ['aaa', 'bbb']
const list: Array<string> = ['ccc', 'ddd']
JavaScript类型 – Object类型

        object对象类型可以用于描述一个对象,如下写法,object表示一个通用的对象,这个时候我们不能从info中获取数据,也不能设置数据。这种写法不推荐。

const info: object = {
    name: 'heart'
}
console.log(info.name) // 错误
info.name = '小王' // 错误
JavaScript类型 – Symbol类型

        在ES5中,如果我们是不可以在对象中添加相同的属性名称的,比如下面的做法:

const persion = {
    name: '小王',
    name: '老王'
}

        通常我们的做法是定义两个不同的属性名字,比如name1,name2。但是我们也可以通过symbol来定义相同的名称,因为Symbol函数返回的是不同的值:

const s1: symbol = Symbol('name')
const s2: symbol = Symbol('name')
const person = {
    [s1]: '小王',
    [s2]: '老王',
}
JavaScript类型 – null和undefined类型

        在 JavaScript 中,undefined 和 null 是两个基本数据类型,在TypeScript中,它们各自的类型也是undefined和null,也就意味着它们既是实际的值,也是自己的类型。

JavaScript类型 –函数
参数的类型注解

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

函数的返回值类型

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

匿名函数的参数

对象类型
 可选类型

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

TypeScript类型 - any类型

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

  • 我们可以对any类型的变量进行任何的操作,包括获取不存在的属性、方法;
  • 我们给一个any类型的变量赋值任何的值,比如数字、字符串的值;
TypeScript类型 - unknown类型 

        unknown是TypeScript中比较特殊的一种类型,它用于描述类型不确定的变量。和any类型有点类似,但是unknown类型的值上做任何事情都是不合法的。因此,unknown在进行任何操作的时候,都需要进行类型校验(缩小),才能根据具体的类型操作

let foo: unknown = 'aaa'
foo = 123 // 合法,unknown可以是任何类型
console.log(foo.length) // 不合法,unknown进行操作时,需要进行类型缩小
if( typeof foo === 'string' ) {
    console.log(foo.length) // 合法,类型缩小后,类型确定了
}

 TypeScript类型 - void类型

        void通常用来指定一个函数是没有返回值的,那么它的返回值就是void类型,我们也可以显示的来指定返回值是void。

tip:我们可以将undefined赋值给void类型,也就是函数可以返回undefined

// 应用场景:用来定义函数的类型
type FooType = () => viod
const foo: FooType = () => {}
TypeScript类型 - never类型

 TypeScript类型 - tuple类型

        tuple和数组区别:

  1. 数组中通常建议存放相同类型的元素,不同类型的元素是不推荐放在数组中。(可以放在对象或者元组中);
  2. 元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型。
const info: [string, number, number] = ['heart', 18, 1.88]

 TypeScript语法细节

联合类型

 

 类型别名

接口的声明

 interface和type区别

 交叉类型

// 交叉类型: 两种(多种)类型要同时满足
type NewType = number & string // 没有意义

// 应用场景
interface IKun {
  name: string
  age: number
}

interface ICoder {
  name: string
  coding: () => void
}

type InfoType = IKun & ICoder

const info: InfoType = {
  name: "why",
  age: 18,
  coding: function() {
    console.log("coding")
  }
}

类型断言as

        TypeScript只允许类型断言转换为 更具体 或者 不太具体 的类型版本,此规则可防止不可能的强制转换 

非空类型断言!

字面量类型

 

类型缩小

  • typeof
  • 平等缩小(比如===、!==)
  • instanceof
  • in 
// 1.typeof: 使用的最多
function printID(id: number | string) {
  if (typeof id === "string") {
    console.log(id.length, id.split(" "))
  } else {
    console.log(id)
  }
}

// 2.===/!==: 方向的类型判断
type Direction = "left" | "right" | "up" | "down"
function switchDirection(direction: Direction) {
  if (direction === "left") {
    console.log("左:", "角色向左移动")
  } else if (direction === "right") {
    console.log("右:", "角色向右移动")
  } else if (direction === "up") {
    console.log("上:", "角色向上移动")
  } else if (direction === "down") {
    console.log("下:", "角色向下移动")
  }
}

// 3. instanceof: 传入一个日期, 打印日期
function printDate(date: string | Date) {
  if (date instanceof Date) {
    console.log(date.getTime())
  } else {
    console.log(date)
  }
}

// 4.in: 判断是否有某一个属性
interface ISwim {
  swim: () => void
}

interface IRun {
  run: () => void
}

function move(animal: ISwim | IRun) {
  if ("swim" in animal) {
    animal.swim()
  } else if ("run" in animal) {
    animal.run()
  }
}

 TypeScript函数类型

         在JavaScript开发中,函数是重要的组成部分,并且函数可以作为一等公民(可以作为参数,也可以作为返回值进行传递)。我们可以编写函数类型的表达式(Function Type Expressions),来表示函数类型。

调用签名(Call Signatures)
构造签名 (Construct Signatures)

 参数的可选类型

 默认参数

 剩余参数

        从ES6开始,JavaScript也支持剩余参数,剩余参数语法允许我们将一个不定数量的参数放到一个数组中。

函数的重载

        在TypeScript中,我们可以去编写不同的重载签名(overload signatures)来表示函数可以以不同的方式进行调用;一般是编写两个或者以上的重载签名,再去编写一个通用的函数以及实现。

 tip:如果需求可以通过联合类型或重载来实现,尽量选择联合类型实现

This
可推导的this类型

this的编译选项
 指定this的类型

 this相关的内置工具

 this相关的内置工具 - ThisType

TypeScript面向对象

认识类的使用

类的定义

类的继承 

类的成员修饰符
        在TypeScript中,类的属性和方法支持三种修饰符: public、private、protected 。public是默认的修饰符。
  • public 修饰的是在任何地方可见、公有的属性或方法,默认编写的属性就是public的;
  • private 修饰的是仅在同一类中可见、私有的属性或方法;
  • protected 修饰的是仅在类自身及子类中可见、受保护的属性或方法; 
只读属性readonly
        如果有一个属性我们不希望外界可以任意的修改,只希望确定值后直接使用,那么可以使用readonly 。
getters/setters

        在前面一些私有属性我们是不能直接访问的,或者某些属性我们想要监听它的获取(getter)和设置(setter)的过程,这个时候我们 可以使用存取器。

class Person {
  // 私有属性: 属性前面会使用_
  private _name: string
  private _age: number

  constructor(name: string, age: number) {
    this._name = name
  }

  // setter/getter: 对属性的访问进行拦截操作
  set name(newValue: string) {
    this._name = newValue
  }

  get name() {
    return this._name
  }
}
const p = new Person("why", 100)
p.name = "kobe"
console.log(p.name)
参数属性(Parameter Properties)

 抽象类abstract

 

 类的类型

        类本身也是可以作为一种数据类型的。下面代码没有报错的原因是:typeScript对于类型检测的时候使用的鸭子类型。

// TypeScript对于类型检测的时候使用的鸭子类型
// 鸭子类型: 如果一只鸟, 走起来像鸭子, 游起来像鸭子, 看起来像鸭子, 那么你可以认为它就是一只鸭子
// 鸭子类型, 只关心属性和行为, 不关心你具体是不是对应的类型

class Person {
  constructor(public name: string, public age: number) {}

  running() {}
}

class Dog {
  constructor(public name: string, public age: number) {}
  running() {}
}

function printPerson(p: Person) {
  console.log(p.name, p.age)
}

printPerson(new Person("why", 18))
printPerson({name: "kobe", age: 30, running: function() {}})
printPerson(new Dog("旺财", 3))
const person: Person = new Dog("果汁", 5)

对象类型的属性修饰符(Property Modifiers)

 索引签名(Index Signatures)

// 索引签名的基本使用

// 案例1
interface InfoType {
  // 索引签名: 可以通过字符串索引, 去获取到一个值, 也是字符串
  [key: string]: string
}
function getInfo(): InfoType {}
const info = getInfo()
console.log(info["name"], info.age, info.address)

// 案例2
interface ICollection {
  [index: number]: string
  length: number
}

function printCollection(collection: ICollection) {
  for (let i = 0; i < collection.length; i++) {
    const item = collection[i]
  }
}

const array = ["abc", "cba", "nba"]
const tuple: [string, string] = ["why", "广州"]
printCollection(array)
printCollection(tuple)

// 索引签名的类型问题

interface IIndexType {
  // 返回值类型的目的是告知通过索引去获取到的值是什么类型
  // [index: number]: string
  // [index: string]: any
  [index: string]: string
}

// 索引签名: [index: number]: string
const names: IIndexType = ["abc", "cba", "nba"]

// 索引签名: [index: string]: any: 没有报错
// 1.索引要求必须是字符串类型 names[0] => names["0"]
const names: IIndexType = ["abc", "cba", "nba"]

// 索引签名: [index: string]: string: 会报错
// 严格字面量赋值检测: ["abc", "cba", "nba"] => Array实例 => names[0] names.forEach
const names: IIndexType = ["abc", "cba", "nba"]
// names["forEach/map/filter"] => function,并非string,所以报错

// 两个索引类型的写法

interface IIndexType {
  [index: number]: string
  [key: string]: any

  // 要求一:下面的写法不允许: 数字类型索引的类型, 必须是字符串类型索引的类型的 子类型
  // 结论: 数字类型必须是比如字符串类型更加确定的类型(需要是字符串类型的子类型)
  // 原因: 所有的数字类型都是会转成字符串类型去对象中获取内容
  // 数字0: number|string, 当我们是一个数字的时候, 既要满足通过number去拿到的内容, 不会和            
  // string拿到的结果矛盾

  // 要求二: 如果索引签名中有定义其他属性, 其他属性返回的类型, 必须符合string类型返回的属性
  // [index: number]: string
  // [key: string]: number|string

  // aaa: string
  // bbb: boolean 错误的类型
}

const names: IIndexType = ["abc", "cba", "nba"]
const item1 = names[0]
const forEachFn = names["forEach"]

names["aaa"]

接口继承

 接口的实现

 抽象类和接口的区别

 严格的字面量赋值检测

interface IPerson {
  name: string
  age: number
}

// 1.奇怪的现象一: 
// 定义info, 类型是IPerson类型
const obj = {
  name: "why",
  age: 18,
  height: 1.88 // 多了一个height属性
}
const info: IPerson = { name: "why", age: 18, height: 1.88 } // 报错
const info: IPerson = obj // 不报错

// 2.奇怪的现象二:
function printPerson(person: IPerson) {}
const kobe = { name: "kobe", age: 30, height: 1.98 }
printPerson({ name: "why", age: 18, height: 1.88 }) // 报错
printPerson(kobe) // 不报错

// 解释现象
// 第一次创建的对象字面量, 称之为fresh(新鲜的)
// 对于新鲜的字面量, 会进行严格的类型检测. 必须完全满足类型的要求(不能有多余的属性)

 TypeScript枚举类型

        枚举类型是为数不多的TypeScript特性有的特性之一:

  • 枚举其实就是将一组可能出现的值,一个个列举出来,定义在一个类型中,这个类型就是枚举类型;
  • 枚举允许开发者定义一组命名常量,常量可以是数字、字符串类型。

 

// 定义枚举类型
enum Direction {
   LEFT = 0,
   RIGHT = 1
 }

enum Direction {
   LEFT = 100,
   RIGHT
}

enum Direction {
  LEFT = "LEFT",
  RIGHT = "RIGHT"
}

enum Operation {
  Read = 1 << 0, // 1
  Write = 1 << 1, // 2
  foo = 1 << 2 // 4
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值