TypeScript技术学习

TypeScript技术学习

TypeScript是微软出品的语言,是js的超集,添加了类型,接口等特性,使用tsc编译器可以将ts编译成js,实际浏览器和服务器上的仍然是js

特性

  • ts会做静态类型检查,编译的时候会报错,但是依然会生成编译文件,有配置文件可以修改,让ts在报错情况下不生成js

数据类型

js中数据类型分为原始数据类型(布尔,数值,字符串,null,undefined,Symbol)和对象类型()

原始类型在ts中的应用

  1. 数值 ,let test:number=123

  2. 布尔,let test:boolean=true

  3. 字符串,let test:string='xxxxxx'

  4. Null,let test:null=null

  5. Undefined ,let test:undefined=null

    注意Null和undefined是所以类型的子类型,也就是其他类型可以被赋值为undefined或者null

任意值

可以使用Any声明任意值,可以任意赋值以及调用属性而不会报错

类型推论

声明并赋值时,没有指定类型的变量会根据赋值做类型推断,没有赋值的声明会被认为是any

联合类型

使用let test: string|number可以声明联合类型,可以将不同类型的值赋予给联合类型,但是联合类型只能掉用两种类型共有的属性和方法。

交叉类型

使用 let test: A & B 可以声明交叉类型,交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。

对象的类型-接口

一般使用

interface Person {
  name:string;
  age:number;
};

let tom :Person={
  name:'xxx',
  age:19
}

ts的接口可以定义对象属性,如上定义的接口,在被继承时不能新增属性,也不能减少属性。

可选属性

interface Person{
  name:string;
  age:number;
  six?:string
}

如上定义的接口,six属性可空

任意类型属性

interface Perons{
    name:string;
    age:number;
    six?:string;
    [propName:string]:string | number;
}

如上定义的接口,可以使用任意属性。需要注意,任意属性的可选类型需要包含已定义属性的类型

只读属性

interface Perons{
    readonly name:string;
    age:number;
    six?:string;
    [propName:string]:string | number;
}

如上定义的接口,属性name为只读属性,不可被重新赋值以及修改。

数组类型

一般使用

let test:number[]=[1,2,3,4,5]

给数组加入任意不符合类型定义的值将会报错

数组泛型

let test:Array<number>=[1,2,3,4,5]

函数类型

函数声明

function test (x:number,y:number):number{
  return x+y;
}

函数表达式

仅对等式右边进行了类型声明,左边使用的实际上是类型推断

let test=function(x:number,y:number):number{
  return x+y;
}

或,对等式两边都进行了类型声明

let test:(x:number,y:number)=>number=function(x:number,y:number):number{
  return x+y;
}

使用接口定义

interface ITest{
    (x:number,y:number):number;
}

let test:ITest;

test=function(x:number,y:number){
    return x+y;
}

可选参数

我们使用?表示表示参数可选,但是可选参数后不能有必选参数

function test(x:number,y:number,z?:number):number{
  if(z!=undefined){
    return x+y+z;
  }
  return x+y
}

参数默认值

当使用默认值时,不受可选参数后不能有必选参数的限制

function test(x:number,y:number,z:number=1)

剩余参数

使用...rest的方式获取剩余参数

function test(x:number,...items:any[])

重载

Ts 会优先匹配前面的定义,因此应该将最精准匹配的放在最前面

function test(x:number):number;
function test(x:string):string;
function test(x:number | string): number| string{
    if(typeof x=='string'){
        return 'xxx';
    }
    return 0;
}

类型断言

类型断言可以手动指定一个值的类型

值 as 类型

类型断言的用途

  1. 将联合类型断言为其中一种类型,从而可以访问这个类型特有的属性。但是要注意这种做法可能会在运行时报错。
  2. 将父类型断言为具体的字类型。
  3. 将变量断言成any从而可以访问任意属性而不报错,前提是你必须确定该对象上存在这个属性
  4. any断言成具体的类型

类型断言的限制

  1. 联合类型可以被断言成具体类型
  2. 父类型可以被断言成具体的子类型
  3. 任何类型可以被断言成any
  4. any可以被断言成人意类型

typescript是结构类型系统,类型之间的对比只会比较他们最终的结构,而忽略他们定义时的关系。

interface Animal{
    name:string
}

interface Cat{
    name:string;
    run():void;
}

let tom:Cat={
    name:'tom',
    run:()=>{
        console.log('run');
    }
}

let animal:Animal=tom;

因为Animal和Cat项目兼容,所以可以使用实现了Cat接口的数据对象给声明为Animal的对象赋值,实际上,Animal和Cat与下面的实现相同

interface Animal{
    name:string
}

interface Cat extends Animal{
    run():void;
}

Animal兼容Cat时,他们就可以互相之间进行类型断言。

双重断言

foo as any as other

将任意类型断言成any再将any断言成其他类型,这在ts编译阶段通常不会报错,但是这种做法其实跳过了类型,需要谨慎使用

类型断言和类型转换

类型断言只是用于TypeScript编译阶段,实际并不会影响对象的类型,在编译成js时类型断言语句会被删除,类型转换需要使用类型转换语句。

声明文件

当使用第三方库时,我们需要引用他的声明文件,才能获得相应的代码补全,接口提示等功能。

声明文件必需以 .d.ts 为后缀。

书写声明文件

  1. declare var 声明全局变量
  2. declare functon声明全局方法
  3. declare class 声明全局类
  4. declare enum声明全局枚举类型
  5. declare namespace声明全局对象
  6. interface 和type声明全局类型

EMCAScript内置对象

EMCAScript标准的内置对象

BooleanErrorDateRegExp 等。

更多的内置对象,可以查看 MDN 的文档

而他们的定义文件,则在 TypeScript 核心库的定义文件中。

DOM和BOM内置对象

DocumentHTMLElementEventNodeList 等。

常用

let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) {
  // Do something
});

类型别名

类型别名用来给一个类型取一个新名字

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
    if (typeof n === 'string') {
        return n;
    } else {
        return n();
    }
}

字符串字面量类型

字符串字面量类型用来约束取值只能是某几个字符串中的一个

type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
    // do something
}

元组

数组合并来相同类型的对象,而元组合并了不同类型的对象。

let tom:[number,string]=[1,'xxx']

越界的元素

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

let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true);//编译报错

枚举

简单的枚举定义

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

枚举成员会被赋值为从0开始递增的数字,同时也会对枚举值到枚举名进行反向映射:

console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true

console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true

手动赋值

我们可以给枚举值手动赋值,值会从手动赋值到数字开始递增,所以要注意覆盖问题。

enum Days {Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 3); // true
console.log(Days["Wed"] === 3); // true
console.log(Days[3] === "Sun"); // false
console.log(Days[3] === "Wed"); // true

TypeScript不会检查手动赋值到覆盖问题,所以需要格外注意。

手动赋值的枚举项可以不是数字

enum Days {Sun = 7, Mon, Tue, Wed, Thu, Fri, Sat = <any>"S"};

手动枚举可以赋值为负数或者小数,后续未手动赋值的项目依然会以1为步长递增

enum Days {Sun = 7, Mon = 1.5, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1.5); // true
console.log(Days["Tue"] === 2.5); // true
console.log(Days["Sat"] === 6.5); // true

常数项和计算所得项

枚举项有两种类型,常数项计算所得项

前面列举的都是常数项,计算所得项如下

enum Color {Red, Green, Blue = "blue".length};

如果在计算所得项后有未手动赋值的枚举项,将会因为无法得到初始值报错

enum Color {Red = "red".length, Green, Blue};

// index.ts(1,33): error TS1061: Enum member must have initializer.
// index.ts(1,40): error TS1061: Enum member must have initializer.

常数枚举

常数枚举是使用const enum 定义的枚举类型

const enum Directions {
    Up,
    Down,
    Left,
    Right
}

let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

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

外部枚举

外部枚举是使用delare enum定义的枚举类型

declare enum Directions {
    Up,
    Down,
    Left,
    Right
}

let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

外部枚举通常出现在声明语句中。

传统方法中,使用构造函数创建类,通过原型链实现继承。在ES6中,我们有了class。

用法与C#等面向对象语言一致。

posted @ 2020-06-05 19:52  我不是陈懋平  阅读(123)  评论(0)    收藏  举报