# 基础

typescript 是静态类型,不像 js 写可以给一个变量赋值任何类型。

JavaScript 是动态类型语言,在运行时进行类型检查。 JavaScript 采用的是词法作用域,函数的作用域在函数定义的时候就决定了。 而与词法作用域相对的是动态作用域,函数的作用域是在函数调用的时候才决定的。 静态类型语言是在编译的时候进行检查

  • JavaScript that scales
  • 静态类型风格的类型系统
  • 从 es6 到 es10 甚至是 esnext 的语法支持
  • 兼容各种浏览器,各种系统,各种服务器,完全开源

# TS 的优势

  • ts 代码可以在开发过程中,发现潜在的问题;编译期间能够发现大部分错误;
  • 更友好的编辑器自动提示
  • 代码语义更清晰易懂,程序更容易理解

对比 js 代码跟 ts 代码,写一段勾股定理的代码:

function demo(data) {
  return Math.sqrt(data.x ** 2 + data.y ** 2)
}
// 如果不传递参数不会检测到,函数会报错
demo()

ts 代码

function tsDemo(data: { x: number; y: number }) {
  return Math.sqrt(data.x ** 2 + data.y ** 2)
}
// 不传递参数会报错
tsDemo({ x: 3, y: 4 })

# 安装

全局安装 ts,输入命令:npm install typescript -g 然后就可以编译 ts 代码了,命令: tsc demo.ts,然后运行命令 node demo.js 运行编译后的代码。 上面的操作有点麻烦,我们可以借助另一个工具 ts-node,输入命令安装:npm install ts-node -g; 再次运行 ts 文件,直接输入命令:ts-node demo.ts

使用 ts-node 进行实时编译

# ts 的静态类型

当一个变量通过静态类型进行定义之后,他就拥有了那个类型的所有属性和方法:

编译使用 tsc a.ts a.ts 是要编译的文件

let a: number = 2
//  a 就拥有了 toFixed valueOf 等等方法

interface Data {
  x: number
  y: number
}
const data: Data = {
  x: 2,
  y: 3,
}
// data 就拥有了 Data 所有的属性和方法

# 类型基础和对象类型

示例代码

// 基础类型 boolean number string void undefined symbol null
const count: number = 123
const tea: string = '123'
// 还有 null、undefined、symbol、boolean、void
// 如果声明和赋值没有在一行,类型推断是不行的
let nu // any
nu = 123

// 这样是可以
let u: number = undefined

// 对象类型 {} class function []
const teacher: {
  name: string,
  age: number
} = {
  name: 'jiegiser',
  age: 18
}
// 数组
const numbers: number[] = [1, 2, 3]
// 类
class Person {

}
const dell: Person = new Person()
// -------------------- 函数
const getTotal: () => number = () => {
  return 123
}

// 类型可以推断 parseInt 返回值为类型 number
const func = (str: string): number => {
  return parseInt(str, 10)
}
// 上面的代码可以写成下面的 -- 下面的返回值类型不能通过类型推断 number
const func1: (str: string) => number = str => {
  return parseInt(str, 10)
}

// ------------函数的参数也可以设置为可选参数,但是可选参数必须要在必选参数后面
// 这样子会报错,可选的只能放在最后面,也可以带默认值
function add(x: numberm y?: number, z: number = 10): number {

}

// 联合类型
let numberOrString: number | string = 123

// 通过类型别名实现联合类型
type NameResolver = () => string
type NameOrResolver = string | NameResolver
function getName(n: NameOrResolver): string {
  if (typeof n === 'string') {
    return n
  } else {
    return n()
  }
}

type 中的 & :

下面代码表明 NativeButton 类型包括 BaseButtonProps 定义的类型以及 React.ButtonHTMLAttributes 定义的类型;

interface BaseButtonProps {
  ...
}
type NativeButton = BaseButtonProps & React.ButtonHTMLAttributes<HTMLELEMENT>

// 如果上面的两个类型都是可选的,可以如下定义
type Na = Partial<BaseButtonProps & React.ButtonHTMLAttributes<HTMLELEMENT>>

# 类型断言

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

# 类型注解和类型推断

// type annotation 类型注解
// type inference 类型推断

// 如果 TS 能够自定分析变量类型,我们就什么也不需要做了
// 如果 TS 无法分析变量类型的话,我们就需要使用类型注解

// 类型注解- 我们来告诉 TS 变量是什么类型
let count: number
count = 123

// 类型推断 - TS 会自动的去尝试分析变量的类型
let countInference = 123

// 可以推断数据类型
const firstNumber = 1
const secondNumber = 2
const total = firstNumber + secondNumber

// 无法分析变量类型
function getTotal(firstNumber, secondNumber) {
  return firstNumber + secondNumber
}

const totals = getTotal(1, 3)

// 定义多个类型
let temp: number | string = 123
temp = '222'

# 函数相关类型

function add(first: number, second: number): number {
  return first + second
}

const total = add(1, 2)

function sayHello(): void {
  console.log('hello')
  // return '' 报错
}

// 函数永远不能执行到最后
function errorEmitter(): never {
  throw new Error()
  console.log(123)
}

function errorEmitters(): never {
  while (true) {}
}

// 解构的类型指定
function adds({ first, second }: { first: number; second: number }): number {
  return first + second
}

const to = adds({
  first: 1,
  second: 2,
})

function getNumber({ first }: { first: number }): number {
  return first
}
const count = getNumber({ first: 1 })

# 数组和元组

# 数组

// 数字数组
const numberArr: number[] = [1, 2, 3]
// 对数组的方法会进行检查
numberArr.push('123') // 会报错
// 数字或字符串数组
const arr: (number | string)[] = [1, 2, '3']
// undefined
const undefinedArr: undefined[] = [undefined]

// 对象数组
// 类型别名 常用在联合类型
// 类型别名 type alias
type User = {
  name: string
  age: number
}

const objectArr: User[] = [
  {
    name: 'jiegiser',
    age: 18,
  },
]

// 也可以用类
class Teacher {
  name: string
  age: number
}
const objectArr1: Teacher[] = [
  new Teacher(),
  {
    name: 'jiegiser',
    age: 18,
  },
]

# 元组

// 元组 tuple
// 只有 3 项,而且可知类型
const teacherInfo: [string, string, number] = ['jiegiser', 'male', 18]

# Interface 接口

定义 Object 类型

  • 对对象的形状(shape)进行描述
  • 对类(class)进行抽象
  • 鸭子类型(Duck Typing)

interface 只做定义不做实现,class 是实现。 类与类之间只能进行单继承,想要实现多继承需要使用 Mixins 的方式 当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。 接口同样会继承到类的 private 和 protected 成员。 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现; 接口继承类也只能进行单继承,想要实现多继承需要使用 Mixins 的方式; Mixins 方式模拟多继承的缺陷

  • 只能在继承一级父类的方法和属性
  • 如果父类中含有同一种方法或属性,会根据赋值的顺序,先赋值的会被覆盖掉

    接口与接口之间可以直接进行多继承 类实现接口可以进行多实现,每个接口用 , 隔开

// interface 和 type 相类似, 但并不完全一致,能用接口表示就用,不能再用类型别名
interface Person {
  // 注意这里的每一个项之间是分号结束
  readonly name: string; // readonly 只读
  age?: number; // 可有可无
  id?: number;
  [propName: string]: any; // 还有其他属性,属性名为string,属性值为任意类型
  say(): string
}
// 类型别名 可以直接表示基础类型
type Person1 = {
  name: string
}
type Person2 = string

const getPersonName = (person: Person): void => {
  console.log(person.name)
}

const serPersonName = (person: Person1, name): void => {
  person.name = name // 提示错误
}

const person = {
  name: 'jiegiser',
  say() {
    return 'say'
  }
}
const person1 = {
  name: 'jiegiser',
  age: 18,
  say() {
    return 'say'
  }
}
getPersonName(person)
getPersonName(person1)
// serPersonName(person)


// 类实现接口
class User implements Person {
  name = 'jiegiser'
  say() {
    return 'hello'
  }
}

// 类实现多接口
  // 动物接口
  interface Animal {
      name: string;

      eat: () => void;
  }

  // 猫科接口
  interface Felidae {
      claw: number;
      run: () => void;
  }

  // 让猫类实现 Animal 和 Felidae 两个接口
  class Cat implements Animal, Felidae {
      name: string;
      claw: number;
      eat() {
          console.log('tag', 'I love eat Food!');
      }

      run: () {
          console.log('tag', 'My speed is very fast!')
      }
  }

  const dog: Dog = new Dog();
  dog.eat();
// 接口之间互相继承
interface Teacher extends Person {
  teach(): string
}

const person2 = {
  name: 'jiegiser',
  say() {
    return 'say'
  },
  teach() {
    return 'teach'
  }
}
const person3 = {
  name: 'jiegiser',
  age: 18,
  say() {
    return 'say'
  },
  teach() {
    return 'teach'
  }
}
const getPersonName1 = (person: Teacher): void => {
  console.log(person.name)
}
getPersonName1(person2)
getPersonName1(person3)

// 接口之间的多继承
interface Ali  {
    pay: () => void
}
interface Tencent {
    game: string
    play: () => void
}
interface Self extends Ali, Tencent {
    name: string
    say: () => void
}

// 接口继承类
class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() { }
}

class TextBox extends Control {
    select() { }
}

// 错误:“Image”类型缺少“state”属性。
class Image implements SelectableControl {
    select() { }
}

class Location {

}

// 接口可以定义函数的类型声明 -- 接口可以代表函数类型
interface SayHi {
  (word: string): string
}

const say: SayHi = (word: string) => {
  return '123'
}

# 类的定义与继承

  • 类(class):定义了一切事物的抽象特点
  • 对象(Object):类的实例
  • 面向对象(OOP)三大特性:封装、继承、多态
class Person {
  name = 'jiegiser'
  getName() {
    return this.name
  }
}
// 继承
class Teacher extends Person {
  constructor() {
    super()
  }
  getTeacherName() {
    return 'jie'
  }
  getName() {
    console.log(this.name)
    // super 调用父类的方法
    return super.getName() + 'jie'
  }
}

const person = new Person()
const teacher = new Teacher()
console.log(person.getName())
console.log(teacher.getTeacherName())
console.log(teacher.getName())

# 类中的访问类型和构造器

# 访问器

// private protected public 访问类型
// public 允许在类的内外被调用
// private 允许在类内被使用-子类也不能访问
// protected 允许在类内及继承的子类中使用
class Person {
  readonly age: number // 只读属性
  public name: string = ''
  say() {
    console.log('hi')
  }
}

class Teacher extends Person {
  constructor() {
    super()
  }
  public sayBye() {
    console.log(this.name)
  }
}

const person = new Person()
person.name = 'jiegiser' // 如果为 private, protected 不能使用
console.log(person.name) // 如果为 private, protected 不能使用
console.log(person.say())

const teacher = new Teacher()
console.log(teacher.sayBye())

# constructor

// constructor
class Person {
  // 传统写法
  // public name: string
  // constructor(name: string) {
  //   // new 的时候去执行
  //   this.name = name
  // }

  // 简化写法
  // 或者下面的写法
  constructor(public name: string) {}
}

const person = new Person('jiegiser')
console.log(person.name)

// super
class Person {
  constructor(public name: string) {}
}

class Teacher extends Person {
  constructor(age: number) {
    super('jiegiser')
  }
}
const teacher = new Teacher(18)
console.log(teacher)

# 静态属性,Setter 和 Getter

static 关键字定义的属性或方法是只能在类上调用,不能在类的实例上调用

class Person {
  // 静态属性
  // private _name: string
  constructor(private _name: string) {}
  // getter
  get getName() {
    // return this.name + 'go' // 这样也可以
    return this._name + ' go' // 这样也可以
  }
  get name() {
    return this._name
  }
  // setter
  set name(name: string) {
    this._name = name
  }
}

const person = new Person('jiegiser')
console.log(person.getName) // 注意这里不用加括号
console.log(person.name) // 注意这里不用加括号
person.name = 'jie'
console.log(person.name) // 注意这里不用加括号

实现一个单例模式

// 单例模式
class Demo {
  private static instance: Demo
  private constructor(public name: string) {}
  // 在类上的方法,不是类的实例上
  static getInstance() {
    if (!this.instance) {
      this.instance = new Demo('name')
    }
    return this.instance
  }
}
const demo1 = Demo.getInstance() // 不能通过 new 创建实例
const demo2 = Demo.getInstance() // 不能通过 new 创建实例
console.log(demo1.name)
console.log(demo1 === demo2)

# 抽象类

class Person {
  private _name: string
  constructor(name: string) {
    this._name = name
  }
  get name() {
    return this._name
  }
}
const person = new Person('jiegiser')
console.log(person.name)

// readonly
class Person {
  public readonly name: string
  constructor(name: string) {
    this.name = name
  }
}
const person = new Person('jiegiser')
person.name = '123' // 只读,不能修改
console.log(person.name)

// 抽象类

// Geom 抽象类--将类中共用的东西抽象出来
abstract class Geom {
  width: number = 1
  getType() {
    return 'Gemo'
  }
  abstract getArea(): number
}

class Circle extends Geom {
  // 抽象方法必须要实现
  getArea() {
    return 123
  }
}

// 接口

interface Person {
  name: string
}

interface Teacher extends Person {
  teacherAge: number
}
interface Student extends Person {
  age: number
}
const teacher = {
  name: 'jie',
  teacherAge: 3,
}

const student = {
  name: 'giser',
  age: 16,
}

// 接口
const getUserIngo = (user: Teacher | Student) => {
  console.log(user.name)
}

getUserIngo(teacher)
getUserIngo(student)

// 类实现接口
interface Radio {
  switchRadio(): void
}
interface Battery {
  checkBatteryStatus()
}
// 要实现 switchRadio 的方法
// 实现两个接口
class Car implements Radio, Battery {
  switchRadio() {}
}

// 接口继承接口
interface RadioWithBattery extends Radio {
  checkBatteryStatus()
}

评 论:

更新: 11/21/2020, 7:00:56 PM