TypeScript学习笔记之基础语法

302 阅读7分钟

TypeScript的定义

TypeScript是js的一个超集(superset),而且拥有类型的机制,而且不能在浏览器直接执行,要编译成js才能执行。

超集(superset)释义:

es6就可以说是es5的一个超集,es6兼容了es5所有的语法,还提出了自己新有的独特的语法特性,意思着es6是es5的超集。所以ts页拥有js的基础特性。

ts静态类型

// js类型 js的类型是动态类型
let a = 123;
a = '123'

//ts类型 ts的类型的静态类型
let b = 123;
b = '123'; // error 会报错 b存储的数字类型,未来存储的也要是数字类型 '123'这个字符串 没办法存储到b

// ts定义类型的写全的写法
let b:number = 123
b = 234

TypeScript带来的优势

  1. 相对js,ts的静态类型使得我们在编写代码时候,帮我们更容易定位发现一些潜在的问题。
  2. ts可以给我们更好的代码提示。
  3. 通过静态类型的定义,让我们更好的阅读代码,代码语义更清晰易懂。
intarfase Point {x:number, y:number}

function tsDemo(data: Point) {
    return Matg.sqrt(data.x ** 2 + data.y ** 2)
}

静态类型的深度理解

我们看见ts的一个静态类型,不仅仅意味着这个变量的类型不能修改,还意味这个变量上属性和方法基本上页锁定了。

类型的基础和对象类型

ts中类型分为基础类型和对象类型

基础类型:

null、undefined、symbol、boolean、void、string、number

对象类型:

函数类型 数组类型 类类型 对象类型

//  基础类型 : null undefined symbol boolean void
const count: number = 123;
const teacherName: string = 'yuzhicheng';

// 对象类型
const obj: {
  name: string;
  age: number;
} = {
  name: 'yzc',
  age: 22
};

// numbers 必须是数字类型的数组
const numbers: number[] = [1, 2, 3];

class Person {}

//  dell 必须是一个 Person类的对象
const dell: Person = new Person();

// getTotal 是一个函数 返回值是一个数组
const getTotal: () => number = () => {
  return 123;
};

类型注解 and 类型推断

类型注解(type annotation):

我们告诉ts变量是什么类型。

let count:number
count = 123

类型推断(type inference):

ts会自动去尝试分析变量的类型

let countInference = 123;

如果ts 能自动分析变量类型,我们就不用做类型注解,如果不能分析变量类型,我们就需要使用类型注解。 写ts代码就是需要每一个变量、每一个对象属性、它们的属性都是固定的。可以用类型推断就用类型推断,不能推断就能用类型注解

函数相关类型

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

// :void 定义了函数没有返回值
function sayHello(): void {
  console.log('hello');
}

// never 定义了函数永远不能执行到最后 完全执行完 也代表没有返回值
function errorEmitter(): never {
  throw new Error();
  console.log(123);
}

// 函数解构的语法
function addfunc({ first, secound }: { first: number; secound: number }) {
  return first + secound;
}

复习

基础类型:

boolean number string void undefined symbol null

定义变量和对变量赋值分开不能进行类型推断

// 这种情况不能类型推断出 count 是数字类型
let count;
count = 123;

对象类型:

{}, Class , function , []

其他例子

// 两种定义函数类型的方式
const func1 = (str:string) => {
    return parseInt(str,10)
}
//定义函数体
const func2: (str: string) => number = str => {
  return parseInt(str, 10);
};

//可能是两种类型 有可能是number 也有可能是string
let temp: number | string = 123;
temp = '456'

数组和元组

数组的注解

//  定义一个数组 元素内容必须是数字类型
const numberArr: number[] = [12, 3];

// 定义一个数组 元素可能是个数字 或者 字符串
const numOrStrArr: (string | number)[] = [12, '3'];

// 定义一个数组 子元素是个对象
const objArr: { name: string; age: number }[] = [
  {
    name: 'dell',
    age: 22
  }
];

// 上面写法 过于繁琐 我们可以定义一个类型别名(type alias) 来实现
type User = { name: string; age: number };
const obj2Arr: User[] = [
  {
    name: 'dell',
    age: 22
  }
];


元祖

元祖能帮助我们约束固定长度 切每个数组元素的类型


// 元祖 tuple
/**
 * 假设我们需要的是一个数组 且数组里面永远只有三个元素 类型固定
 * 这时候数组不能帮我们约束这种类型,ts提供了元组的类型
 */

const teacherInfo: (number | string)[] = [1, 'male', 18];

// 元组 tuple
const teacherInfo2: [string, string, number] = ['dd', 'dd', 2];

// 元组和数组的结合 
// 使用场景 csv Excel导出的文件格式
const teacherlist: [string, string, number][] = [
  ['dd', 'dd', 19],
  ['dd', 'dd', 19],
  ['dd', 'dd', 19],
  ['dd', 'dd', 19]
];

Interface 接口

接口只是在我们开发过程中,ts帮我们做语法提示和校验的工具,编译成js代码的时候会剔除 没有体现。

类型别名 和 接口的区别:

ts 规范中 我们能用interface 接口 去表诉一个类型 就尽量用interface 实在不行我们才去用alias 类型别名

// 可以直接代表一个基础类型 接口不可以
type Person = string

//  我们可以用interface 定义通用的类型 。
// 有通用型的类型集合 我们可以用 interface 去表现出来
interface Person {
  name: string;
  age?: number; // 表示可有可无 可选参数
  [propName: string]: any; // 表示 Person 这个类型集合 还可以有其他属性 数组的名字是个字符串就行 类型是any
  say(): string; // 表示这个集合 有个say的方法 返回值是个 string
}

// 类型 别名
type Person1 = {
  name: string;
};

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

const setPersonName = (person: Person, name: string) => {
  person.name = name;
};

const person = {
  name: 'name',
  sex: 'male',
  say() {
    return '';
  }
};

getPersonName(person);

// getPersonName({
//   name:'yzc',
//   sex:'3' //err ts 在对字面量赋值的时候会强校验
// )

setPersonName(person, 'les');

// 类去应用一个接口
// 类要应用一个接口 就必须要有 接口里面定义的方法 和属性
class User implements Person {
  name = 'dell';
  say() {
    return 'hellp';
  }
}

// 接口互相之间实现继承
interface Teacher extends Person {
  teach(): string;
}

// interface定义一个函数类型
interface SayHi {
  (str: string): string;
}

const sayhi: SayHi = str => {
  return 'hi';
};

类的定义与实现

类的继承

extends关键字实现类的继承 当我们重写类的方法 可以用super 关键字去调用父类中被重写的那个方法。

class Person {
  name = 'yzc';
  getName() {
    return this.name;
  }
}

// 类实现继承
class Teacher extends Person {
  getTeacher() {
    return 'Teacher';
  }
  getName() {
    // 类继承的时候 我们重写了getName 方法 可以用super 关键字 调用父类的getName 方法
    return super.getName() + 'lee';
  }
}

类中的访问类型和构造器

public:

公开的,允许在类的内外被调用。

private:

私有的,允许在类内被调用。

protected:

受保护的,允许在类内 及 继承的子类中使用。

constructor 构造器


class Person {
  // 传统写法
  // public name: string;
  // //  类在创造实例的时候被执行
  // constructor(name: string) {
  //   this.name = name;
  // }
  // 简化写法
  constructor(public name: string) {}
}

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

class Teacher extends Person {
  // 当父类有contructor 方法 子类也有contructor 子类必须要用super  去实现父类的 的contractor
  // 子类 要使用 contractor 构造器 不管父类有没有 contractor 都必须要用 super() 
  constructor(public age: number) {
    super('yzc');
  }
  say() {
    console.log(this.name);
  }
}
const teacher = new Teacher(12);
teacher.say();

静态属性 setter getter

**
 * getter对私有属性 做加密 或者其他处理再对外使用
 * setter 对外暴露 一个 对 私有属性的写入 我们可以在
 * setter 创建的方法里面做处理
 */

class Person {
  constructor(private _name: string) {}

  // getter
  get name() {
    return this._name + 'lee';
  }
  // setter
  set name(name: string) {
    const realName = name.split(' ')[0];
    this._name = realName;
  }
}

const person = new Person('dell');
// get的特性 不需要写 方法的 调用 getName

console.log(person.name);
person.name = 'yzc lee';
console.log(person.name);

static 静态属性

静态属性 把方法或者属性 挂在类上 而不是实例上

静态属性 实现单例模式


// 单例模式 一个类永远只有一个实例
class Demo {
  // 私有的静态属性
  private static instance: Demo;
  // 要实现单例模式 就不允许 外部 通过new 关键字实例化
  private constructor(public name: string) {}

  // 静态属性  把方法 挂在类上 而不是实例上
  static getInstance(name) {
    // return new Demo();
    if (!this.instance) {
      this.instance = new Demo(name);
    }

    return this.instance;
  }
}

const demo1 = Demo.getInstance('yzc');
const demo2 = Demo.getInstance('sxy');
console.log(demo1.name);
console.log(demo2.name);

抽象类

readonly 关键字 限制公有属性 只能读不能改

抽象类 abstract

很多类 有相同的通性 我们就可以用抽象类 把这些通性 抽象出来

abstract class Geom {
  // 如果 这些 类 的 getArea 的实现都是不一样的 我们可以 抽象 这个方法
  // 抽象 方法 意味者这个方法的具体实现是抽象 的 不能直接去写它的实现 只能去定义它
  abstract getArea(): number;
  // 页可以写一些 属性和方法的具体实现
  getType() {
    return 'Geom';
  }
  width: number;
}
// 抽象类 只能被继承 不能被实例
// 子类继承了 抽象类 必须要去实现它的抽象方法
class Cirtcle extends Geom {
  getArea() {
    return 134;
  }
}
class Square {}

class Triangle {}