TS 进阶

上篇: TS基础数组

类型的别名 type

type strAria = string; // 给 string 类型定义了 strAria别名
const str: strAria = 'abc';

type fnAria = () => string;
function (callback:fnAria):void {
    callback();
}
复制代码

字符串字面量类型

type EventName = 'xm' | 'xh' | 'xb';
const str : EventName = 'xb'
const elseStr : EventName = 'xf' // error, 不在这几个名字当中
复制代码

咱们使用 type 定了一个字符串字面量类型 EventNames,它只能取三种字符串中的一种。函数

注意,类型别名与字符串字面量类型都是使用 type 进行定义。post

元组

一个带有不一样值的数组ui

let confusion: [string,number] = ['a',1]; // 这就叫元组
复制代码
let confusion: [string, number];
confusion[0] = 'a'; // 能够只赋值给某一项
confusion[1] = 'b' // error , 元组的第2项必须为 number

// 若是直接给元组赋值,要彻底提供其定义好的类型和长度
confusion = ['a',1]
复制代码

越界的元素

当添加越界的元素时,它的类型会被限制为元组中每一个类型的联合类型:this

let xcatliu: [string, number];
xcatliu = ['Xcat Liu', 25]; // ok
xcatliu.push('http://xcatliu.com/'); // ok
xcatliu.push(true); // error, 不能添加非字符串和 number 的值
复制代码

枚举 Enum

用于定义一个类型的值在必定的范围内spa

使用 enum 定义枚举code

枚举的成员从0开始递增,而且key 和 value 会互相映射xml

enum Colors { Red, Yellow, Blue }
Colors['Red'] === 0 // true 从0开始递增
Colors[0] === 'Red' // 相互映射

// 枚举事实上会编译成以下
var Color;
(function (Color) {
    Color[Color["Red"] = 0] = "Red";
    Color[Color["Yellow"] = 1] = "Yellow";
    Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));
复制代码
  • 手动赋值

枚举的值是能够二次赋值的,被从新赋值的后一项会接着上一项的key递增对象

若是两个枚举值重复了,不会报错,可是值会被覆盖继承

能够为小数或者负数,递增步数仍然为 1

配合断言,可让枚举不是数字

enum Colors { Red = 1, Yellow, Blue }
Colors['Red'] = 2 // 从新赋值
Colors['Yellow'] // 3 下一项 + 1

Colors['Yellow'] = 1 // 此时 Red 和 Blue 值重复了, Colors[2] 只会取最后的值,由于覆盖了。
console.log(Colors[2] === "Red"); // false
console.log(Colors[2] === "Blue"); // true

// 负数
Colors['Red'] = 2.1
Colors['Yellow'] // 3.1
复制代码
  • 断言
enum Colors { Red = 1, Yellow, Blue = <any>"S" } Colors['Blue'] // 'S' 复制代码

计算所得项

上面咱们使用的枚举都是常数项

计算所得项就是经过计算赋值的枚举,只在编译阶段求值

enum Colors { Red = 1, Yellow, Blue = 1 + 1 }

// 因为编译时求值 计算所得项的后一项若是没有赋值,会由于没法得到初始值报错
enum Colors { Red = 'asdasd'.length, Yellow, Blue } // error 

复制代码

当知足如下条件时,枚举成员被看成是常数:

  • 不具备初始化函数而且以前的枚举成员是常数(单纯声明的时候)。在这种状况下,当前枚举成员的值为上一个枚举成员的值加 1。但第一个枚举元素是个例外。若是它没有初始化方法,那么它的初始值为 0
  • 使用常数枚举表达式初始化。常数枚举表达式是 TypeScript 表达式的子集,它能够在编译阶段求值。当一个表达式知足下面条件之一时,它就是一个常数枚举表达式:
    • 数字字面量 => Red = 1
    • 引用以前定义的常数枚举成员(能够是在不一样的枚举类型中定义的)若是这个成员是在同一个枚举类型中定义的,可使用非限定名来引用
    • 带括号的常数枚举表达式
    • +, -, ~ 一元运算符应用于常数枚举表达式
    • +, -, *, /, %, <<, >>, >>>, &, |, ^ 二元运算符,常数枚举表达式作为其一个操做对象。若常数枚举表达式求值后为 NaN 或 Infinity,则会在编译阶段报错

全部其它状况的枚举成员被看成是须要计算得出的值。

  • 被当成是常量的例子
enum Colors { Red, Yellow, Blue }
// Colors['Red'] ==> 0 Colors['Yellow'] ==> 1 Colors['Blue'] ==> 2

enum Directions { 
	Up = 996,
    Down = Up,
    Left = Colors['Red'],
    Right = (1 + 1),
    UpLeft = 2 % 1,
    DownLeft = 'a' - 1// 结果 NaN 报错
}
复制代码

常数枚举

使用 const enum 定义的枚举

常数枚举与普通枚举的区别是,它会在编译阶段被删除,而且不能包含计算成员。

const enum Color {Red, Green, Blue = "blue".length};// error 不能包含计算成员
复制代码

外部枚举

使用 declare enum 定义的枚举类型

declare 定义的类型只会用于编译时的检查,编译结果中会被删除。

外部枚举与声明语句同样,常出如今声明文件中。

同时使用 declareconst 也是能够的:

类与接口 implements

类用于面向对象

接口用于对象形状的描述

不一样的类之间某一部分可能行为一致,那么为了避免重复写两个同样的接口,可使用implements 实现重用interface

implements 中文译为 "实现"

好比有个狗类,有个猫类,它们都有 eat 这个方法,实现的形状一致

interface Behavior {
    eat(food: string): void
}

class Dog implements Behavior {
  eat(foot) {}    
}
class Cat implements Behavior {
  eat(foot) {}
}

class habaDog extends Dog implements Behavior {
  // 此时哈巴狗继承了狗类,就有了 eat 方法 
}
复制代码
  • 多个实现
interface Behavior { // 行为接口
  eat(food: string): void
}

interface Appearance { // 外表接口
  fur:string
}

class Dog implements Behavior {
  eat(foot) {}    
}

class habaDog extends Dog implements Behavior, Appearance {
    fur = ''  
}
复制代码

接口继承

接口也是能够继承接口的

继承老爸姓名

interface Fa {
  surname: string
}

interface Son extends Fa {
  name: string
}

const obj: Son = {
  surname : 'z',
  name: 'zc'
}
复制代码

接口继承class

用于将某个 class 定义为类型,并往上再添加类型。

class Fa {
  constructor() {}
  suck(){

  }
}

interface Son extends Fa {
  suck():void;
  name: string;
}

复制代码

泛型

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

使用 <T> 表明类型的变量, T 只是约定用法,能够任意指定。

function getArrVal<T>(something:T):Array<T> {
  return [something];
}

getArrVal<string>('z') // ['z'] 使用时再指定类型
getArrVal('z') // 不写也没事 ts 会推论出来

// 接口型定义
interface Test<T> {
  num : T
}
let o : Test<string> = {
  num: '1'
}
复制代码
  • 能够一次性定义多个泛型
interface Test<T,U> {
  name?: T,
  num : U
}
let o : Test<string,number> = {
  num: 1
}

function Test<T,U> (a:T,b:U):void { // 函数定义
  console.log(a,b);
  
}
Test<string,number>('1',1)
复制代码

泛型约束

泛型没法知道具体的类型,因此没法操做它的属性和方法

function Test<T> (a:T):void {
  console.log(a.length);  // error
}
Test<string>('1')
复制代码

当你明确知道泛型中有哪些属性方法时,能够经过 extends 进行泛型约束,写在声明函数名的后面

interface hasLengthProp {
    length : number;
}
function Test<T extends hasLengthProp>(a:T):void {
    console.log(a.length);
}
复制代码
  • 泛型能够约束泛型

至关于泛型的继承

function test<T extends U,U>(a:T,b:U):void {
    console.log(a);
}

test({a:1,b:2,c:3},{a:1,b:2})
复制代码

泛型接口

在接口中定义泛型,若是接口中只定义了一个匿名函数的类型,直接赋值便可。

interface Test {
  <T>(name:T):void
}
let say:Test; // 直接赋值

say = function<T>(name:T):void {
  console.log(name);
}
say('haha')
复制代码

若是接口中包含多个属性,这个接口就是一个对象的描述

interface Test {
  demo<T>(name:T):void;
  a:string;
}
let say:Test; // 对象的描述

say.demo = function<T>(name:T):void {
  console.log(name);
}
say.demo('haha')
复制代码

泛型类

就是在泛型里面使用类型变量 类那节说过,类有两部分:静态部分和实例部分。 泛型类指的是实例部分的类型,因此类的静态属性不能使用这个泛型类型

class Name<T>{
  num:T;
  constructor(num:T) {
    this.num = num
  }
  add:(x:T,y:T) => T;
}
let addName = new Name<number>(10)
addName.num = 10
addName.add = (x:number,y:number) => {
  return 1+2
}
复制代码

泛型默认值

当代码中没有直接指定,而且类型推论也没有成功时,默认值会生效

function say<T = any>(name: T):void {
    alert(name)
}
say<string>('1') // ok
say(true) // ok
复制代码

声明合并

就是说声明两个一样的接口、类或者函数,会进行合并操做。

合并的属性的类型必须是惟一的

interface Alarm {
    price: number;
     alert(s: string): string;
}
interface Alarm {
    weight: number;
    alert(s: string, n: number): string;
}
===> 至关于
interface Alarm {
    price: number;
    weight: number;
   	alert(s: string, n: number): string;
}
复制代码
相关文章
相关标签/搜索