欢迎光临
我们一直在努力

TypeScript 简明学习

安装 Typescript

Typescript 官网地址: https://www.typescriptlang.org/zh/

使用 nvm 来管理 node 版本: https://github.com/nvm-sh/nvm

安装 Typescript:

npm install -g typescript

使用 tsc 全局命令:

// 查看 tsc 版本
tsc -v
// 编译 ts 文件
tsc fileName.ts

原始数据类型

Typescript 文档地址:Basic Types

Javascript 类型分类:

原始数据类型 - primitive values:

  • Boolean
  • Null
  • Undefined
  • Number
  • BigInt
  • String
  • Symbol
// Boolean 类型
let isDone: boolean = true;

// Number 类型 ES6支持二进制和八进制
let age: number = 26;
let binaryNumber: number = 0b11;
let octalNumber: number = 0o17;

// 字符串类型
let firstName: string = "san";
let middleName: string = "ren";
let lastName: string = "yan";
let message: string = `my name is ${firstName}${middleName}${lastName}`;

// undefin 与 null
let u: undefined = undefined;
let n: null = null;

// undefined 和 null 类型是所有类型的子类型
// 也就是说 undefined 可以复制给number类型的变量
// 下面这些都是可行的
let num: number = undefined;
let num2: number = null;
let str: string = undefined;
let str2: string = null;
let bool: boolean = undefined;
let bool2: boolean = null;

any 类型

let notSure: any = 4
notSure = 'maybe it is a string'
notSure = 'boolean'
// 在任意值上访问任何属性都是允许的:
notSure.myName
// 也允许调用任何方法:
notSure.getName()

Array 和 Tuple(元组)

Typescript 文档地址:Array 和 Tuple

// 如下表示 arrOfNumbers 是一个数组
// 且数组中只允许存在number类型
// 另外 arrOfNumbers 也只允许添加(push) number类型
let arrOfNumbers: number[] = [1, 2, 3, 4];

// 元组的表示和数组相似
// 元组将类型写在里面 一一对应
// 如果少写一项会报错
// 多写一项也会报错
let tupleArr: [number, String] = [1, "sanrenyan"];

// 以下多写、少写都会报错
// tupleArr = [1,'1',3]
// tupleArr = [1]

interface 接口

Typescript 文档地址:Interface

Duck Typing 概念:

如果某个东西长得像鸭子,像鸭子一样游泳,像鸭子一样嘎嘎叫,那它就可以被看成是一只鸭子。

// 定义一个接口 Person
interface Person {
  name: string;
  age: number;
}

// 基于 Person 接口 定义变量 viking
// 少写多写 都会报错
let viking: Person = {
  name: "sanrenyan",
  age: 26,
};

// 如果我们希望接口中是一个可选属性
// 可以写成下面 number 这样
interface Person2 {
  name: string;
  age?: number;
}

// 如果我们希望一些属性是只读的
// 即只有定义时被赋值 后面不可修改
// 那么就可以使用 readonly 定义
interface Person3 {
  name: string;
  age: number;
  readonly loveName: string;
}

函数

Typescript 文档地址:Functions

// TS中 我们会约束函数的输入输出
// 如下 我们会约定 add 的输入和输出只能是 number
function add(x: number, y: number): number {
  return x + y;
}
// 如果我们参数是不定的怎么办?
// 比较好的方法是引入可选参数
function add2(x: number, y: number, z?: number): number {
  if (typeof z === "number") {
    return x + y + z;
  }
  return x + y;
}

// 直接定义函数完整的动态类型 包括输入和输出
let add3: (x: number, y: number, z?: number) => number;

add3 = (age: number, age2: number) => {
  return age + age2;
};

// 通过 interface 描述函数类型
interface ISum {
  (x: number, y: number): number;
}

const sum: ISum = (x: number, y: number) => {
  return x + y;
};
  • 函数省略参数的类型,typescript 会默认这个参数是 any 类型;
  • 函数省略返回值的类型,那么当函数无返回值时,默认函数返回 void 类型,当函数有返回值时,typescript 会根据我们定义的逻辑推断出返回值的类型。

类型推论、联合类型、类型断言

Typescript 文档地址:类型推论 - type inference

联合类型 - union types

// 设置联合类型
// 如果TS不确定一个联合类型是哪个类型时
// 我们只能访问联合类型内所有类型的共有属性和方法
let numberOrString: number | string;
// 只被允许使用下面三个共有方法 当前不能调用 变量未赋值
numberOrString.toString()
numberOrString.valueOf()
numberOrString.toLocaleString()

// 变量赋值number类型后  就可以使用number 类型的方法了
numberOrString = 0.332;
let numberTofixed = numberOrString.toFixed(2);
console.log(numberTofixed); // 0.33

类型断言 - type assertions

// 类型断言
// 通过as关键字告诉TS编辑器变量的类型
// 这样就可以使用该类型下的方法了
function getLength(input: string | number) {
  const str = input as string;
  if (str.length) {
    return str.length;
  } else {
    const number = input as number;
    return number.toString().length;
  }
}

类型守卫 - type guard

// typescript 在不同的条件分支里面,智能的缩小了范围,这样我们代码出错的几率就大大的降低了。
function getLength2(input: string | number): number {
  if (typeof input === 'string') {
    return input.length
  } else {
    return input.toString().length
  }
}

类型守卫(类型保护)有一些限制,这些 typeof 类型保护只有两种形式能被识别: typeof v === "typename"typeof v !== "typename""typename"必须是 "number""string""boolean""symbol"。 TypeScript并不会阻止我们与其它字符串比较,只是不会把那些表达式识别为类型保护。

Class 类

面向对象编程的三大特点

  • 封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,
  • 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性。
  • 多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。

类 - Class

// 面向对象三大特点:封装、继承、多态
class Animal {
  name:string;
  constructor(name:string){
    this.name = name
  }
  run(){
    return `${this.name} is runing`
  }
}
const snake = new Animal('snake')

// 继承
class Dog extends Animal{
  bark() {
    return `${this.name} is barking`
  }
}

const wangcai = new Dog('wangcai')
console.log(wangcai.run());
console.log(wangcai.bark());

// 重写构造函数 必须使用super调用父类方法
class Cat extends Animal {
  constructor(name:string){
    super(name)
  }
  run() {
    return `Cat run ** ${super.run()}`
  }
}

const maomi = new Cat('xiaomaomi')
console.log(maomi.run());

类成员的访问修饰符

  • public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
  • private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
  • protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的

类与接口

类实现一个接口

interface Radio {
  switchRadio(trigger: boolean): void;
}
class Car implements Radio {
  switchRadio(trigger) {
    return 123
  }
}
class Cellphone implements Radio {
  switchRadio() {
  }
}

interface Battery {
  checkBatteryStatus(): void;
}

// 要实现多个接口,只需要中间用 逗号 隔开即可。
class Cellphone implements Radio, Battery {
  switchRadio() {
  }
  checkBatteryStatus() {

  }
}

枚举 Enums

枚举 Enums

// 数字枚举,一个数字枚举可以用 enum 这个关键词来定义,我们定义一系列的方向,然后这里面的值,枚举成员会被赋值为从 0 开始递增的数字
enum Direction {
  Up,
  Down,
  Left,
  Right,
}
console.log(Direction.Up)

// 还有一个神奇的点是这个枚举还做了反向映射
console.log(Direction[0])

// 字符串枚举
enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',
}
const value = 'UP'
if (value === Direction.Up) {
  console.log('go up!')
}

泛型 Generics

泛型 Generics

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

function echo(arg) {
  return arg
}
const result = echo(123)
// 这时候我们发现了一个问题,我们传入了数字,但是返回了 any

function echo<T>(arg: T): T {
  return arg
}
const result = echo(123)

// 泛型也可以传入多个值
function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]]
}

const result = swap(['string', 123])

泛型第二部分 - 泛型约束

在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法

function echoWithArr<T>(arg: T): T {
  console.log(arg.length)
  return arg
}

// 上例中,泛型 T 不一定包含属性 length,我们可以给他传入任意类型,当然有些不包括 length 属性,那样就会报错

interface IWithLength {
  length: number;
}
function echoWithLength<T extends IWithLength>(arg: T): T {
  console.log(arg.length)
  return arg
}

echoWithLength('str')
const result3 = echoWithLength({length: 10})
const result4 = echoWithLength([1, 2, 3])

泛型第三部分 - 泛型与类和接口

class Queue {
  private data = [];
  push(item) {
    return this.data.push(item)
  }
  pop() {
    return this.data.shift()
  }
}

const queue = new Queue()
queue.push(1)
queue.push('str')
console.log(queue.pop().toFixed())
console.log(queue.pop().toFixed())

//在上述代码中存在一个问题,它允许你向队列中添加任何类型的数据,当然,当数据被弹出队列时,也可以是任意类型。在上面的示例中,看起来人们可以向队列中添加string 类型的数据,但是那么在使用的过程中,就会出现我们无法捕捉到的错误,

class Queue<T> {
  private data = [];
  push(item: T) {
    return this.data.push(item)
  }
  pop(): T {
    return this.data.shift()
  }
}
const queue = new Queue<number>()

//泛型和 interface
interface KeyPair<T, U> {
  key: T;
  value: U;
}

let kp1: KeyPair<number, string> = { key: 1, value: "str"}
let kp2: KeyPair<string, number> = { key: "str", value: 123}

类型别名 和 交叉类型

类型别名 Type Aliases

类型别名,就是给类型起一个别名,让它可以更方便的被重用。

let sum: (x: number, y: number) => number
const result = sum(1,2)
type PlusType = (x: number, y: number) => number
let sum2: PlusType

// 支持联合类型
type StrOrNumber = string | number
let result2: StrOrNumber = '123'
result2 = 123

// 字符串字面量
type Directions = 'Up' | 'Down' | 'Left' | 'Right'
let toWhere: Directions = 'Up'

交叉类型 Intersection Types

interface IName  {
  name: string
}
type IPerson = IName & { age: number }
let person: IPerson = { name: 'hello', age: 12}

赞(1) 打赏
未经允许不得转载:散人研 » TypeScript 简明学习
分享到: 更多 (0)

评论 抢沙发

6 + 9 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏