根本数据类型

数字

const a: number = 1;

字符串

const b: string = '1';

数组

const c: number[] = [1, 2, 3];const d: Array<number> = [1, 2, 3];const e: any[] = [1, '2', true];

布尔

const f: boolean = true;

对象

const g: object = {};

undefined

罕用于组合类型

const h: number | undefined;
null
const i: null;

元组

可为数组中的每个参数定义绝对应的类型

const j: [number, string] = [1, '2'];

枚举

enum err {  first = 3,  'second',}const k: e = err.first;console.log(g); // 4

tips

  1. 如果未赋值的上一个值是数字,那么这个未赋值的值就是上一个值 +1
  2. 如果未赋值的上一个值未赋值,那么输入的就是它的下标
  3. 如果未赋值的上一个值是非数字,那么必须赋值

void

指定办法类型,示意没有返回值,办法体中不能有return

function add(): void {  console.log('add');}// 如果办法体有返回值,能够加上返回值的类型function delete: string {  return 'delete';}

never

其余类型(包含undefind和null)的子类型,代表从不会呈现的值

let o: never;o = (() => {  throw new Error('error msg');})();

任意类型

让参数能够是任何一种类型

let p: any = 1;p = '2';p = true;

函数

函数申明

function add(): vide {}

办法参数

function getUserInfo(name: string, age?: number, school: string = '哈佛大学'): string {  return `name: ${name}, age: ${age || '年龄不详'}, school: ${string}`;}
tips
?代表这个参数可不传,不传即为undefined,也可定义默认值

残余参数

function sum(a: number, b: number, ...arr: number[]): number {  let sum: number = a + b;  arr.forEach(i => {    sum += i;  });    console.log(arr); // [3, 4, 5]  return sum;}console.log(sum(1, 2, 3, 4, 5)); // 15

函数重载

不同的数据类型
function reload(name: string): void {}function reload(age: number): void {}function reload(info: any): any {  if (typeof(info) === 'string') {    console.log(`我的名字是: ${info}`);  } else if (typeof(info) === 'number') {    console.log(`我的年龄是: ${info}`);  }}reload('Clearlove'); // 我的名字是Clearlovereload(18); // 我的年龄是18
不同的参数
function reload(name: string): voidfunction reload(name: string, age?: number): voidfunction reload(name: any, age? number): any {  if (age) {    console.log(`我的名字是: ${name}, 往年${age}岁!!`);  } else {    console.log(`大家好,我的名字是: ${name}`);  }}reload('Clearlove'); // 大家好,我的名字是Clearlovereload('Clearlove', 18); // 我的名字是Clearlove, 往年18岁!!

tips

  1. 被重载的函数,是没有函数体的,能够依据参数的类型走其中一个办法并判断参数
  2. 函数的重载与返回值类型无关
  3. 函数重载的作用:是一种参数校验性能,在进行函数调用时,会对参数进行查看,只有传人的参数类型、程序、个数和重载的函数的参数雷同时,能力调用胜利,否则报错

class Person {  // 公有变量  private name: string;    // 构造函数  constructor(name: string) {    this.name = name;  }    getName(): string {    return this.name;  }    setName(name: sring): void {    this.name = name;  }}const myBoy = new Person('Clearlove');console.log(myBoy.getName()); // ClearlovemyBoy.setName('test');

继承

class Son extends Person {  // 动态属性  public static age: number = 18;    // 学校  public school: string;    constructor(name: string, school: string) {    // 拜访派生类的构造函数前,必须调用“super”,初始化父类构造函数,并把参数传给父类    super(name);    this.school = school;  }    // 静态方法  static run(name: string): string {    return `${name}在跑步,他是年龄是${this.age}`;  }}const son = new Son('Clearlove', '清华大学');son.setName('Test');console.log(son);console.log(Son.run('Clearlove')); // Clearlove在跑步,他的年龄是18console.log(Son.age); // 18

tips

  1. public 在以后类、子类和类以外都能够拜访
  2. protected 在以后类、子类外部都能够拜访,类内部无法访问
  3. private 在以后类外部能够拜访,子类和类内部无法访问
  4. 属性不加修饰符,默认都是public

多态

通过形象办法/办法重载,实现多态。多态的作用是用来定义规范
// 形象父类

abstract class Animal {  // 公有属性  private name: string;  constructor(name: string) {    this.name = name;  }  // 形象成员: 办法  abstract eat(): any;  // 形象成员: 属性  protected abstract ages: number;   sleep(): void {    console.log(`${this.name}在睡觉`);  }}class Cat extends Animal {  ages: number = 2;  constructor(name: string) {    super(name);  }  // 非抽象类: Cat 不会主动实现继承自: Animal类的形象办法: eat, 必须手动定义父类中的形象办法,着就是多态  eat(): string {    return '猫吃鱼';  }  sleep(): string {    return '猫在睡觉';  }}const cat = new Cat('Tom');cat.sleep();

tips

  1. 抽象类无奈 实例化
  2. 非抽象类继承父类时,不会主动实现 来自父类的形象成员,必须手动定义 父类中的成员,否则会报错
  3. 形象成员蕴含 属性办法

接口

在面向对象的编程中,接口是一种标准的定义,它定义了行为和动作的标准。
在程序设计外面,接口起到了一种限度和标准的作用。
接口定义了某一批类所需恪守的标准,接口不用关怀这些类的外部状态数据,也不关怀这些类里办法的实现细节,它只规定这批类必须提供某些办法,提供这些办法的类就能够满足理论须要。ts中的接口相似java,同时还减少了更灵便的接口类型,包含属性、函数、可索引和类等。

属性接口

interface InterfaceName {  first: string;  second?: string;}function logParam(name: InterfaceName): viod {  console.log(name.first, name.second. 'test');}const obj = { first: '1', second: '2'. three: '3' };logParam({ first: '1', second: '2'. three: '3' }); // 报错,只能传接口定义的值logParam(obj);
tips
用变量存储数据,这样能够传入定义的接口外的值,否则如果间接传入对象中无接口定义的值会报错

#### 函数类型接口
对函数传入的参数类型,以及返回值类型进行束缚,可批量进行束缚

interface keyMap {  (key: string, value: string): string;}let logKeyMap: keyMap = fucntion (key: string, value: string): string {  return key + value;}console.log(logKeyMao('key', 'value'));
tips
接口只对传入的参数的类型和参数的个数进行束缚,不对参数名称进行束缚

可索引接口

  • 束缚数组
interface Arr {  [index: number]: string;}let test: Arr = ['123'];
  • 束缚对象
interface Obj {  [index: string]: string;}let test: Obj = { name: 'Clearlove' };

tips

  1. 数组 进行束缚,index必须是 number类型
  2. 对象 进行束缚,index必须是 string类型
  3. 索引签名参数类型必须为string或者number

类类型接口

  • 进行束缚,相似 抽象类 的实现
interface Ainmal {  name: string;  eat(): void;}calss Dogs implements Animal {  name: string;  constructor(name: string) {    this.name = name;  }  eat() {}}
  • 接口继承(接口能够继承接口)
interface Dog {  ear(): void;}interface Persons entexds Dog {  work(): void;}class Cat {  code() {    console.log('猫在敲代码');  }}class SuperMan extends Cat implements Persons {  eat(): void {    console.log('eat');  }  work(): void {    console.log('work');  }}const man = new SuperMan();man.code();
tips
类接口会对类的 属性办法进行束缚,相似非抽象类继承类时必须实现某些办法和属性,但对于属性和办法的类型束缚更加严格。除了办法 void类型 可被 从新定义外,其余属性或办法的类型定义须要和接口保持一致。

泛型

软件工程中,咱们不仅要创立统一的、定义良好的API, 同时也要思考重用性。
组件不仅可能反对以后的数据类型,同时也能反对将来的数据类型,在创立大型零碎时为你提供了非常灵便的性能。
泛型就是解决 接口办法复用性,以及对不特定数据类型的反对。
要求:传入的参数和返回的参数统一

函数的泛型

function getDate<T>(value: T): T {  return value;}const val = getDate<number>(123);console.log(val);
tips
这里的T 能够改成其余任意值,但定义的值和传入的参数以及返回的值是一样的。个别默认写法是T,也是业内标准的抉择。

类的泛型

class MainClass<T> {  public list: T[] = [];  add(value: T): void {    this.list.push(value);  }  min(): T {    let minNum = this.list[0];    for(let i = 0; i < this.list.length; i++) {      minNum < this.list[i] ? minNum : this.list[i];    }    return minNum;  }}// 实例化类,指定类的T的类型是numberconst minClass = new MainClass<number>();minClass.add(1);minClass.add(2);minClass.add(3);console.log(minClass.min());// 实例化类,并指定了类的T的类型是string,则其办法的传参和返回值都是string类型let minClass2 = new MainClass<string>();minClass2.add('1');minClass2.add('2');minClass2.add('3');console.log(minClass2.min());

接口的泛型

  • 第一种写法
interface Config {  // 标准参数类型和返回值类型  <T>(value: T): T;}let getDate: Config = function <T>(value: T): T {  return value;}const data = getData<string>('123');console.log(data);
  • 第二种写法
interface Config<T> {  // 标准参数和返回值类型  (value: T): T}// 接口办法function getData<T>(value: T): T {  return value;}// 应用接口let myGetData: Config<string> = getData;consoie.log(myGetData('123'));
tips
接口的泛型只针对函数类型的接口

类当做参数传入泛型类

class User {  username: string | undefined;  password: string | undefined;  constructor(params: {    usermame: string | undefined,    password?: string | undefined  }) {    this.username = params.username;    this.password = params.password;  }}class Db<T> {  add(user: T): boolean {    console.log(user);    return true;  }  updated(user: T, id: number): boolean {    console.log(user, id);    return true;  }}let user = new User({  username: 'Clearlove'});user.password = '123';let db = new Db<User>();db.add(user);db.updated(user, 1);
tips
类的参数名和类型都做了束缚

模块

外部模块成为命名空间,内部模块简称为模块,模块在起本身的作用域里执行,而不是在全局作用域。
定义在一个模块里的变量、函数、类等在模块外是不可见的,除非你明确的应用export模式导出它们。
对应的,如果想应用其余模块导出的变量、函数、类等,须要导入它们,能够应用import

// modules/db.tsfunction getData(): any[] {  console.log('获取数据');  return [    {      userName: '张三'    },    {      userName: '李四    }  ];}// 一个模块能够应用屡次export { getData };// 一个模块只能应用一次export default getData;
import { getData as getDbData } from './modules/db';import getDbData from './modules/db';getDbData();
tips
浏览器中不能间接应用,可在nodewebpack的环境中调试

命名空间

在代码量较大的状况下,为了防止各种变量命名抵触,可将类似性能的函数、类、接口等搁置到命名空间内。TypeScript的命名空间能够将代码包裹起来,只对外部裸露须要在内部拜访的对象。
命名空间和模块的区别:

  • 命名空间: 外部模块,次要用于组织代码,防止命名抵触
  • 模块: ts内部模块的简称,偏重代码的复用,一个模块里可能会有多个命名空间
// modules/Animal.tsexport namespace A {  interface Animal {    name: string;    say(): void;  }  export class Dog implements Animal {    name: string;    constructor(name: string) {      this.name = name;    }    say() {      console.log(`我是${this.name}`);    }  }}export namespace B {  interface Animal {    name: string;    eat(): void;  }  export class Dog implements Animal {    name: string;    constructor(name: string) {      this.name = name;    }    say() {      console.log(`Hello, my name is ${this.name}`);    }  }}
import {A, B} from './modules/Animal';const dog = new A.Dog('小马');dog.say();

装璜器

装璜器实质上是一种非凡的函数,被利用在于:

  • 类属性
  • 类办法
  • 类拜访器
  • 类办法的参数

所以利用装璜器其实很想是组合一系列函数,相似于高阶函数和类。
装璜器的语法非常简略,只须要在想应用的装璜器后面加上@符号,装璜器就会被利用到指标上:

function simpleDecorator() {  console.log('i am a decorator!');}@simpleDecoratorclass A {}

一共有5种装璜器能够被咱们应用:

  1. 类装璜器
  2. 属性装璜器
  3. 办法装璜器
  4. 拜访器装璜器
  5. 参数装璜器
@classDecoratorclass Bird {  // 属性装璜器  @propertyDecorator  name: string;  // 办法装璜器  @methodDecorator  fly (    // 参数装璜器    @parameterDecorator    meters: number  ) {}  // 拜访器装璜器  @accessorDecorator  get egg() {}}

执行

机会

装璜器只在解析执行时利用一次,例如:

function f() {  console.log('apply decotator');  return true;}@fclass A {}// output: apply decorator

这里的代码会在终端中打印apply decorator,即便咱们其实并没有应用类A

执行程序

不同类型的装璜器执行程序是明确定义的:

  1. 实例成员: 参数装璜器-> 办法/拜访器/属性 装璜器
  2. 动态成员: 参数装璜器-> 办法/拜访器/属性 装璜器
  3. 结构器:参数装璜器
  4. 类装璜器

例如:

function f(key: string) {  console.log(`evaluate: ${key}`);  return function() {    console.log(`call: ${key}`);  }}@f('class Decorator')class A {  @f('Static Property')  static prop?: number;  @f('Static Method')  static method(@f('Static Methos Parameter') foo) {}  constructor(@f('Constructor Parameter') foo) {}  @f('Instance Method')  method(@f('Instance Mthdos Parameter') foo) {}  @f('Instance Propterty')  prop?: number;}// evaluate Inastance Method// evaluate Inastance Method Parameter// call: Instace Method Parameter// call: Instace Method// evaluate Inastance Property// call: Inastance Property// evaluate Static Property// call: Static Property// evaluate Static Method// evaluate Static Method Parameter// call: Static Method Parameter// call: Static Method// evaluate: Class Decorator// evaluate: Constructor Decorator// call: Constructor Decorator// call: Class Decorator

你兴许会留神到,执行实例属性prop晚于实例办法method。然而执行动态属性static prop早于静态方法static method

这是因为对于属性/办法/拜访器 装璜器而言,执行程序取决于它们的申明程序

然而,同一办法中不同参数的装璜器的执行程序是相同的,最初一个参数的装璜器会被先执行:

function f(key: string) {  console.log(`evaluate: ${key}`);  return function () {    console.log(`call: ${key}`);  }}class A {  method() {    @f('Parameter Foo') foo,    @f('Parameter Bar') bar  } {}}// evaluate Parameter Foo// evaluate Parameter Bar// call Parameter Bar// call Parameter Foo

多个装璜器的组合

能够对同一个指标利用多个装璜器,它们的组合程序为:

  1. 求值外层装璜器
  2. 求值内层装璜器
  3. 调用内层装璜器
  4. 调用外层装璜器

例如:

function f(key: string) {  console.log(`evaluate: ${key}`);  return function () {    console.log(`call: ${key}`);  }}class A {  @f('Outer Method')  @f('Inner Method')  method() {}}// evaluate: Outer Method// evaluate: Inner Method// call: Inner Method// call: Outer Method

定义

类装璜器

利用于类结构器,其参数类的构造函数

function addAge(args: number) {  return function(target: Function) {    target.prototype.age = args;  }}@addAge(18)class Hello {  name: string;  age: number;  constructor() {    console.log('Hello World');    this.name = 'Clearlove';  }}console.log(Hello.prototype.age); // 18const hello = new Hello();console.log(hello.age); // 18

办法装璜器

它会被利用到办法的属性描述符上,能够用来监督、批改或者替换办法定义。
办法装璜器会在运行时传入下列三个参数:

  1. 对于动态成员来: 类的构造函数,对于实例成员:类的原型对象
  2. 成员的名字
  3. 成员的属性描述符(value: any, writable: boolean, enumerable: boolean, configurabel: boolean)
function addAge(constructor: Function) {  constructor.prototype.age = 18;}function method(tagrget: any, propertyKey: string, descriptor: PropertyDescriptor) {  console.log(target);  console.log(`prop: ${propertyKey}`);  console.log(`desc: ${JSON.stringify(descriptor)}` + '\n\n');}@addAgeclass Hello {  name: string;  age: number;  constructor() {    console.log('Hello World');    this.name = 'Clearlove';  }  @method  hello(): string {    return 'Instance method';  }  @method  static sayHello(): string {    return 'Static method';  }}// Hello {hello: [Function]}// prop: hello// desc: {"writabel": true, "enumerabel": true, "configurable": true}// { [Function: Hello] seyHello: [Function] }// prop: sayHello/// desc: {"writabel": true, "enumerabel": true, "configurable": true} 

如果润饰的是hello这个实例办法,第一个参数就是原型对象,也就是Hello.prototype。
退出润饰的是sayHello这个静态方法,第一个参数就是结构器constructor

拜访器装璜器

拜访器装璜器利用于拜访器的属性描述符,可用于察看、批改或替换访问者的定义。
拜访器不能再申明文件中应用,也不能在任何其余环境上下文中应用(例如在申明类中)。

拜访器装璜器表达式会在运行时当作函数被调用,传人下列三个参数:

  1. 动态成员: 类的构造函数,实例成员: 类的原型对象
  2. 成员的名字
  3. 成员的属性描述符

例子:

function configurabele(value: boolean) {  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {    descriptor.configurabel = value;  }}class Point {  private _x: number;  private _y: number;  constructor(x: number, y: number) {    this._x = x;    this._y = y;  }  @configurable(false)  get _x() { return this_.x; }  @configurable(false)  get _y() { return this._y; }}

属性装璜器

属性装璜器表达式会在运行时当作函数被调用,传人下列2个参数:

  1. 动态成员: 类的构造函数,实例成员: 类的原型对象
  2. 成员的名称
function log(target: any, propertyKey: string) {  let value = target[properttKey];  const getter = function () {    console.log(`Getter for ${propertyKey} returned ${value}`);    return value;  }  const setter = function (newVal) {    console.log(`Set ${propertyKey} to ${newVa;}`);    value = newVal;  }  if (delete this[propertyKey]) {    Object.defineProperty(target, propertyKey, {      get: getter,      set: setter,      enumerable: true,      configurable: true    });  }}class Calculator {  @log  public num: number;  square() {    this.num * this.num;  }}const cal = new Calculator();cal.num = 2;console.log(cal.square);// Set num to 2// Getter for num returned 2// Getter for num returned 2// 4

办法参数装璜器

参数装璜器表达式会在运行时当作函数被调用,传入下列3个参数:

  1. 动态成员: 类的构造函数,实例成员: 类的原型对象
  2. 参数的名称
  3. 参数再函数参数列表的索引
const parseConf = [];// 在函数调用前执行格式化操作function parseFunc(target: any, name, descriptor) {  const originalMethod = descriptor.value;  descriptor.value = function (...args: any[]) {    for (let index = 0; index < parseConf.length; index++) {      const type = parseConf[index];      console.log(type);      switch (type) {        case 'number':          args[index] = Number(args[index]);          break;        case 'string':          args[index] = String(args[index]);          break;        case 'boolean':          args[index] = String(args[index]) === 'true';          break;      }      return originalMethod.apply(this, args);    }  };  return descriptor;}// 向全局对象中增加对应的格式化信息function parse(type) {  return function (target, name, index) {    parseConf[index] = type;    console.log('parseConf[index]:', type);  };}class Modal {  @parseFunc  public addOne(@parse('number') num) {    console.log('num:', num);    return num + 1;  }}let modal = new Modal();console.log(modal.addOne('10')); // 11