typescript - 简解

141 阅读6分钟

是什么:

TypeScript是微软开发的一个开源的编程语言,通过在JavaScript的基础上添加静态类型定义构建而成。通过TypeScript编译器或Babel转译为JavaScript代码,可运行在任何浏览器,任何操作系统。

www.tslang.cn/docs/handbo…

ts中冒号(:)后面的都是指定类型作用

为什么:

  • 程序更容易理解 - 适用于大型长期维护项目
  • 效率更高 - 丰富接口等
  • 更少的错误
  • 包容性强 - 完全兼容js

怎么做:

安装和调试:

npm install -g typescript
tsc -v //检查版本

tsc xxx.ts //生成对应js

npm install -g ts-node //ts-node可直接编译ts文件

ts类型

  • boolean(布尔值)
  • number(数字)
  • string(字符串)
  • symbol(symbol类型)
  • undefined(undefined类型)
  • null(null类型)
  • void(没有任何类型)
  • any(任何类型)
  • never(表示的是那些永不存在的值的类型,例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never类型,当它们被永不为真的类型保护所约束时。)
  • object(object表示非原始类型,也就是除numberstringbooleansymbolnullundefined之外的类型。)
  • number[]或Array<number>(数组)
  • let aa: [number, string] = [11, ‘aa’](元组 Tuple-元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。)
  • enum(枚举)- 双向映射
  • <T>(泛型),包含约束泛型
  • 内置类型 - ts封装了很多
enum EnumList { //加const称为常量枚举,常量值才可以使用常量枚举 const enum EnumList {...}
    up,
    right, //1 会随着前面的值递增
    down, //2
    left
}

console.log(EnumList.up) //0
console.log(EnumList[0]) //up
//普通泛型
function echo<T>(arg: T): T {
    return arg;
}
const result = echo(true);
console.log(result); //true

//约束泛型
interface IWithLength {
    length: number
}
function echoWithLength<T extends IWithLength>(arg: T): T {
    console.log(arg.length); //3
    return arg;
}
console.log(echoWithLength([1,2,3])); //[1,2,3]

//类和接口使用泛型
class GetMin<T>{
    arr: T[] = [];
    add(item: T) {
        this.arr.push(item);
    }
    min(): T {
        var min = this.arr[0];
        this.arr.forEach(function (value) {
            if (value < min) {
                min = value;
            }
        });
        return min;
    }
}
var gm1 = new GetMin<number>();
gm1.add(5);
gm1.add(3);
console.log(gm1.min()); //3

interface KeyPair<T, U> {
    key: T,
    value: U
}
let k1: KeyPair<number, string> = { key: 1, value: 'string' } 

类和接口

TS中类新增:

  1. public - 共有属性或方法
  2. private - 私有属性或方法-只有我可访问
  3. protected - 受保护的属性或方法-只有我和我的子类可访问

1. 类型接口:

  1. 接口可以约束类的定义
  2. 类必须实现接口的全部定义,可以新增额外的属性和方法
  3. 接口只能约束类的公有成员
  4. 接口不能约束类的构造函数
interface PersonInterface {
    readonly id: number, //只读属性,const是对象的内存空间不可改变,readonly是对象内某属性不可改变
    name: string,
    age?: number  //?:指可选
}

let viki: PersonInterface = {
    id: 1,
    name: 'viki',
    age: 18
}

2. 接口的接触,可以实现单个接口或者同时继承多个接口

3. 接口继承类

  1. 相当于接口把类的成员都抽象了出来,也就是只有类的成员结构,没有类的实现
  2. 接口继承类, 可以把类的公有成员,私有成员, 受保护成员,抽离出来
interface Human {
    name : string;
    eat () : void;
}

class Asian implements Human { // 使接口在类里生效用implements
    constructor(name : string) {
        this.name = name;
    }
    name : string;
    eat(): void {
    }
}

interface Man extends Human{ //接口继承用extends
    run() : void;
}

interface IsChild {
    cry() : void;
}

interface Boy extends Man , IsChild {
}

let boy : Boy = {
    name : "" ,
    run(): void {
    },
    eat(): void {
    },
    cry(): void {
    }
}

class Auto {
    state = 1;
}

//接口AutoInterface继承了Auto类,那么这个接口就隐式的有state这个属性
interface AutoInterface extends Auto{

}

class C implements AutoInterface {
    state = 1;
}

class Auto2 {
    state = 1;
    // private state2 = 0;//C2报错
}

//接口AutoInterface继承了Auto类,那么这个接口就隐式的有state这个属性
interface AutoInterface2 extends Auto2{

}

class C2 implements AutoInterface2 {
    state = 1;
}

//Bus继承了Auto2,且使用了AutoInterface,AutoInterface接口
//Bus继承Auto2的时候,把state也继承了下来,所以隐式的有这个属性,从而不会因为使用了接口,而保持没有找到这个属性
class Bus extends Auto2 implements AutoInterface{

}

类型别名:

// 类型别名与interface都可以认为是对'参数'的封装

//声明一个type
type Alice = {
    name: string,
    age: number
}
//使用这个type
const alice: Alice = {
    name: '小蛮',
    age: 18
}

字面量(在枚举中,经常会遇到一些常量值,字面量是一种简单的方法来处理一种情形,下面的Directions有四个方向,下面的towWhere会把这四种类型限定在里面。其他值是不被允许的,而且输入的时候有自动提示):

字面量:是一个特殊的类型,这个类型只能是一个原始数据类型

// const str: 'name' = 'name2' //会提示不能将类型“"name2"”分配给类型“"name"”。
const number: 1 = 1
type Directions = 'Up' | 'Down' | 'Left' | 'Right'
let toWhere: Directions = "Up"
console.log(toWhere) //Up

联合类型(交叉类型):

  • interface的扩展
  • interface 组合扩展的时候使用type 将类型联合扩展起来
interface IName {
    name: string
}
type IPerson = IName & { age: number }
let person1: IPerson = { name: '小明', age: 10 }

声明文件:

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

声明语句

declare var jQuery: (selector: string) => any;

jQuery('#foo');

上例中,declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。它编译结果是:

jQuery('#foo');

声明文件

通常我们会把声明语句放到一个单独的文件(jQuery.d.ts)中,这就是声明文件, 声明文件必需以 .d.ts 为后缀。

// src/jQuery.d.ts

declare var jQuery: (selector: string) => any;
// src/index.ts

jQuery('#foo');

一般来说,ts 会解析项目中所有的 *.ts 文件,当然也包含以 .d.ts 结尾的文件。所以当我们将 jQuery.d.ts 放到项目中时,其他所有 *.ts 文件就都可以获得 jQuery 的类型定义了。

/path/to/project
├── src
|  ├── index.ts
|  └── jQuery.d.ts
└── tsconfig.json

假如仍然无法解析,那么可以检查下 tsconfig.json 中的 filesinclude 和 exclude 配置,确保其包含了 jQuery.d.ts 文件。

注意点:

  • 动态类型语言(运行期间才去做数据类型检查):js,python等
  • 静态类型语言(编译其间确定数据类型):java,C#等

ts常见概念:

  • 类型推断(ts在不指定类型时会自动进行类型推断)
  • 联合类型(多种类型 - string | number
  • 类型断言(多类型时,可指定类型进行操作 - xxx as string / xxx as HTMLElement

函数写法:

//函数声明写法
function add(...): number {
    ...
}

//函数表达式写法
const add = (...): number => {
    ...
}