TypeScript系统学习笔记

一、基本类型

ts支持跟js一样所有的基本类型,此外还增加了枚举类型使用。
布尔值、number(二进制、十进制、八进制等)、字符串、数组(指定数组类型 let arr:number[]=[1,2,3];元组 let arr:[number,string] = [10,‘haha’])、Object、
枚举:enum类型是对js基本类型的一个补充,使用枚举可以为一组数值提供赋予友好的名字

eg:  
enum:Color = {Red,Green,Blue}  
let c:Color = Color.Green;
//默认情况下,从0开始为元素编号,也可以为名字指定值
enum Color = {Red = 2,Green};
let colorName:string = Color[2];//Red

Any:
任何类型,在指定的变量类型不确定或返回的类型不确定时使用,可以让编译器不对类型进行检查,可以是任何类型。

Void:
void类型跟any类型正好相反,它表示没有任何类型。当一个函数没有返回值时,通常指定返回值类型是void。

Null和undfined
null和undifined跟js一样,也具有这两个基本类型,且此两个类型是任何其他基本类型的子类型,可以赋值给任何类型。

let a:number = null  
let b:void = null  

never:
nerver类型代表着永远没有返回值,通常给异常函数进行使用或者根本没有返回值的函数使用,never类型是所有基本类型的子类型,其他类型都可以是never值,但是never值不可以是其他任何类型的值。

类型断言:
类型断言就是告诉编译器不用进行编译时校验,采取相信程序员的类型标记。

//类型断言有两种声明方式  
1、尖括号语法  
let someString:any = 'hahaha';
let strLength:number = (<string>someString).length;

2、as语法
let someString:any = 'hahaha';
let strLength:number = (someString as string).length;//jsx时只能使用此语法

二、变量声明

ts变量声明跟ES6 js变量声明一致,也是const及let、类型解构;

//对象解构  
let {a:newName1,b:newName2} = o
// o={
   a:1,
   b:2
}
//也可指定类型
let {a,b}:{a:number,b:string} = o

三、接口

1、接口就是ts里用于指定组合类型的,里面可以组合各种类型,然后组合为接口。指定一个变量为这个接口类型。

interface LabelledValue{
    label:string
}

function printLabel(labelObject:LabelledValue){
    console.log(labelObject.label)
}
let myObj = {size:10,label:'hahaha'}
printLabel(myObj)

接口内只要传入的类型有接口里面具有的类型,就匹配成功,接口内还有多个其他类型属性也不影响。还可以专门指定接口内的属性为可选属性。

2、可选属性:可选属性跟普通属性差不多,只是属性名后多了一个?。

interface LabelledValue{
    label:string,
    val?:number
}

function printLabel(labelObject:LabelledValue){
    console.log(labelObject.label)
}
let myObj = {size:10,label:'hahaha'}
printLabel(myObj)

3、只读属性:在变量名前指定readonly,即表明此属性,只能在创建时被赋值一次,以后再也不能被更改了。

interface LabelledValue{
    readonly label:string,
    val?:number
}
//ts具有ReadonlyArray<T>类型,它与Array<T>相似,只是不可变,也可以确保数组创建后不能被修改
let a:number[] = [1,2,3,4];
let ro:ReadonlyArray<number> = a;
rop[0] = 12;//error

4、函数类型:可以定义函数类型的接口,定义函数的入参类型,返回类型

interface SearchFunc{
    (source:string,subString:string) : boolean;
}
let mySearch:SearchFunc;
mySearch = function(src:string,sub:string):boolean{//入参名可以与定义的接口不一致,但是各参数的类型需一致
    let result = src.search(sub);
    return result > -1;
}

5、可索引的类型:可索引类型具有一个索引签名,它描述了对象索引的类型,以及相应索引的返回值。

interface StringArray{
    [index:number]:string
}
let myArray:StringArray;
myArray = ['a','b'];
let myStr:string = myArray[0];

6、类类型:与java等类似,也可以使用类类型来明确强制一个类的类型

interface ClockInterface{
    currentTime:Date;
    setTime(d:Date);
}
class Clock implements ClockInterface{
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h:number,m:number){

    }
}

7、继承接口:接口与类一样,也可以进行继承。

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;

8、混合接口;接口继承类

四、函数

ts中的函数跟js中的函数几乎一致,并且提供了一些拓展;
1、函数类型

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

let myAdd = function(x: number, y: number): number { return x + y; };
//完整函数类型
参数类型与返回类型组成完整函数类型,只要参数类型一致,参数名并不进行校验;左边ts会自动进行推断,因此完整的函数类型如下;
let myAdd:(baseValue:number,increment:number) => number = function(x: number, y: number): number { return x + y; };

2、可选参数
js里面的参数是可选的,如果没有进行赋值,会是undefined;但ts里面指明的参数都是必须的,但是可以指定可选参数,可选参数跟js的参数一样,可以不传。

function buildName(firstName:string,last?:string):string{

}
//可选参数必须在必须参数后面;
//ts中也可指定参数默认值,参数默认值指定方法跟js一致,默认参数可以在必须参数之前,但是传值时,如果不传默认的值,必须传undefinded;

3、剩余参数
跟在js中传入可拓展参数一样,剩余参数可以不传或传任意个

function buildName(firstName:string,...lastName:string[]):string{

}

4、重载
ts的函数还可以进行重载,那么ts的接口就有多态,重载两种状态。ts的重载会根据传入的参数类型,自动选择合适的返回类型状态。

function pickCard(x:{suit:string;card:number}[]):number;
function pickCard(x:number):{suit:string;card:number};
function pickCard(x):any{
    
}
//pickCard有两种重载状态,根据传入的参数是number还是Object进行选择;在描述重载状态时,应把最确定的放最上面,这样ts编译时能快速找到;

五、类

1、es6开始提供了类,ts中也支持类,并且更加友好,更接近面向对象的用法。

class Greeter{
    greetingf:string;
    constructor(message:string){
        this.greeting = message;
    }
    greet(){
        return "Hello," + this.greeting;
    }
}
let greet = new Greeter("world");

2、继承
ts原生就支持类,并且支持面向对象用法,因此也支持继承模式

class Animal {//基类 / 超类
    name:string
    constructor(name:string){
        this.name = name;
    }
    move(distanceInMeters: number = 0) {
        console.log(`Animal moved ${distanceInMeters}m.`);
    }
}

class Dog extends Animal {//派生类 / 子类
    bark() {
        console.log('Woof! Woof!');
    }
}

class Snak extends Animal{
    constructor(name:string){//派生类 / 子类里的构造函数必须调用super,代表调用基类的构造函数。ts规定。
        super(name)
    }
}

3、公有、私有与受保护类型
ts跟其他面向对象的编程一样,类中所有的属性,构造函数,函数都可以指定类型;
公有类型:public 关键字默认不写,不写即默认为public,本类及子类及本子类的实例都能够访问;
私有类型:private 需要属性名前书写,私有类型只能在本类内进行访问;

class Animal {//基类 / 超类
    private name:string
    constructor(name:string){
        this.name = name;
    }
    move(distanceInMeters: number = 0) {
        console.log(`Animal moved ${distanceInMeters}m.`);
    }
}

受保护类型:protected 需要属性名前书写,受保护类型只能在本类及派生类内进行访问,本类实例及派生类实例也不能进行访问;

class Animal {//基类 / 超类
    protected name:string
    constructor(name:string){
        this.name = name;
    }
}

//readonly 只读属性,只可读访问,不可修改

class Animal {//基类 / 超类
    readonly name:string
    constructor(name:string){
        this.name = name;
    }
}

4、存取器-即get set操作
ts允许在类中定义存取器,即get set操作

let passcode = 'secret passcode'
class Employee{
    private _fullName:string;
    
    get fullName():string{
        return this._fullName;
    }
    
    set fullName(newName:string):string{
        if(passcode == 'secret passcode'){
            this._fullName = newName;
        }else{
            consolo.log("Error")
        }
    }
}

5、静态属性
一般情况类内指定的属性都为实例初始化时才执行的属性,严格意义上属于实例的属性,也可以通过指定静态属性,此属性为类的属性。通过 类名.静态属性名 才能在类中进行访问

class Grid {
    static origin = {x:0,y:0};
    calOrigin(point:{x:number;y:number}){
        let x = (point.x - Grid.origin.x)
    }
    constructor (public scale:number)
}

6、抽象类
ts中可以定义抽象类作为基类,抽象类中也可以定义抽象方法,定义的抽象方法只能在子类中实现,抽象类不能实例化。而基于抽象类的子类实例也不能调用抽象类中没有的方法。
抽象类及抽象方法使用 abstract 关键字定义

abstract class Department {
    constructor(public name :string){
        
    }
    abstract printMeeting():void //必须在派生类中实现
}
class AccDep extends Department {
    constructor(){//基类必须调用
        super('acc');
    }
    printMeeting():void{
        console.log(123);
    }
    report():void{//此方法即使定义了,AccDep的实例也不能进行调用
        console.log(456);
    }
}

六、泛型

1、ts类似与java存在泛型来设置一些重复的组件,譬如函数。ts中的泛型类似于any,可以指代任何类型的值,但跟any不同的是,泛型只是指代传入的类型,而any是不确定类型。泛型使用类型变量T表示,而此类型变量只是指定类型,不表示值。

function identity<T>(arg:T):T{//泛型函数
    return arg
}
//使用
(1)指定传入类型
let i = identity<string>("haha")
(2)类型推论--即编译器自动判别
let i = identity("haha")

//可以用于表示T数组 T[]
function identity<T>(arg:T[]):T[]{//泛型函数
    return arg
}

2、泛型接口,泛型接口思想跟泛型函数类似

interface Gen{
    <T>(arg:T):T;
}
function identiy<T>(arg:T):T{
    
}
ler i:Gen = i;//调用i时参数确认类型

interface Gen<T>{
    (arg:T):T;
}
function identiy<T>(arg:T):T{
    
}
ler i:Gen<number> = i;//整个接口泛型T指定统一类型

3、泛型类,泛型类思想跟泛型函数及泛型接口类似

class Gen<T>{//只有实例部分可以使用泛型,静态部分不能,因为静态部分不是由外部操控,只能类内操作,属于类内。
    value:T
}
let i = new Gen<number>()//整个类指定泛型类型,更加直观

4、泛型约束
有时候,并不希望所有的类型都能符合要求,这个时候就可以对泛型进行约束,只有符合条件的才行。

//最常见的是使用接口进行约束
interface lengthwise{
    length:number;
}
function log<T extends lengthwise>(arg:T):T{
    
}

七、枚举

枚举是一组变量名的集合,可以为其指定值。
1、数字枚举,指定值或开始值,如果开始值是number,则自动开始递增,如果不指定,则第一个自动从0开始。

enum Direction {
    one=1,
    two,//2
    three//3
}
//若不指定one=1,则one=0,two=2,three=3
//访问数据枚举
Direction.two = 2

2、字符串枚举
字符串枚举不会进行自递增

enum Direction {
    one='first',
    two='second',//second
    three='third'//third
}
//若不指定one=1,则one=0,two=2,three=3
//访问数据枚举
Direction.two = second

极少情况下才将数字枚举与字符串枚举进行混合。
3、枚举成员按值的求法分为常量成员和计算成员
值为常量的或常量引用的等为常量成员;
表达式等的为计算成员;
数字枚举可以从枚举值反向映射枚举值;
常量枚举,常量枚举对象成员只能是常量枚举表达式:

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

let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
//且编译阶段就会被删除,内联到引用的代码处

八、类型兼容性

ts的组合类型为结构性类型,跟java的名义类型不一样,不要求两个结构完全一摸一样才能进行赋值或传参。只要x要兼容y,那么y中至少具有与x中相同的属性,可多,不可少。

interface Named{
    name:string;
}
let x : string;
let y = {name:'a',location:'l'}
x=y//通过编译
//函数传参也同理;

九、高级类型

1、交叉类型:交叉类型代表多个类型的联合体,使用&,表示一个对象或此处类型为联合类型。
例如, Person & Serializable & Loggable同时是 Person 和 Serializable 和 Loggable。 就是说这个类型的对象同时拥有了这三种类型的成员。

2、联合类型:表示一个值可以是几种类型之一。 我们用竖线( |)分隔每个类型,所以 number | string | boolean表示一个值可以是 number, string,或 boolean。

3、用户自定义的类型保护,ts里类型保护就是一些表达式,运行时检查每个作用域里的类型。
定义一个检查函数,返回值是一个类型谓词

function isFish(pet:Fish | Bird):pet is Fish{
    return (<Fish>pet).swim !== undefined;
}

十、模块

ts中的模块与es6中的模块思想是一致的。模块内的内容只有模块内可用,export出去的话外部可用。若没有export,也没有import,则为全局内容。
//commonJs与AMD里的exports变量,即等于es6内的export default;ts使用export = 表示;使用 import x = require(‘xxx.ts’)

class test{
    
}
export = test

import t = require('test.ts')

可以在导出文件内,再次导出第三方模块;

import {a} from 'a.ts';
....
export {a} from 'a.ts'

十一、命名空间

1、ts中的命名空间,即同一文件内,指定一个内部作用域空间。此空间内变量都是此内部作用域的,如需访问需抛出内部变量/类/方法;使用 空间名.作用名 。

namespace Validation {
    export interface stringValidation {//外部需要使用需要export导出
        isAcceptable(s:string):boolean
    }
    const lttersRegexp = /^[A-Za-z]+$/;//外部不需要使用,外部也无法访问
    export class LettersOnlyValidator implements stringValidation {
        isAcceptable(s: string) {
            return lttersRegexp.test(s);
        }
    } 
}
let strings = ["Hello", "98052", "101"];
let validator : {[s:string]:Validation.stringValidation} = {};//外部访问要使用 空间名.导出变量 访问
validator["letter"] = new Validation.LettersOnlyValidator();

2、同一命名空间分布于多文件内
同一命名空间内的代码可以分段分布于多文件内,引用时使用引用即可

//one.ts
namespace Validation {
    export interface stringValidation {//外部需要使用需要export导出
        isAcceptable(s:string):boolean
    }
}

//two.ts
namespace Validation {
    const lttersRegexp = /^[A-Za-z]+$/;//外部不需要使用,外部也无法访问
    export class LettersOnlyValidator implements stringValidation {
        isAcceptable(s: string) {
            return lttersRegexp.test(s);
        }
    } 
}

//test.ts
<reference path="one.ts">
<reference path="two.ts">
let strings = ["Hello", "98052", "101"];
let validator : {[s:string]:Validation.stringValidation} = {};//外部访问要使用 空间名.导出变量 访问
validator["letter"] = new Validation.LettersOnlyValidator();

十二、声明合并

ts会把同名的命名空间、接口等进行合并,形成一个并集。
1、合并接口
同名的接口声明会自动进行合并,如果两个同名声明存在同样的非函数成员,则这两个成员必须类型一致。
接口的合并,是后来合并的接口内成员靠前。
2、合并命名空间
命名空间的合并与接口类似,但是只合并导出的成员,未导出的成员,仍然只能在原始的命名空间内进行访问。
3、同名的命名空间还能与同名的类、接口、枚举等合并,但合并的内部同名成员类型需要相同。

十三、装饰器

1、装饰器可以对类或其他方法添加额外的特性支持,或修改类及其成员。@xxx为装饰器声明,通常声明在标注的元素(类)前。xxx为一个函数,参数为被装饰的声明信息。

@sealed
Class s{
    
}

function sealed(target){//target即为Class s
    
}

//实际上通常创建一个装饰器工厂函数,返回一个表达式,以供装饰器运行时调用
function color(v:string){//这是一个装饰器工厂
    return function (target){//这是一个装饰器
        
    }
}

2、多个装饰器;当具有多个装饰器修饰同一个声明时,由上而下依次对装饰器表达式求值(即返回装饰器函数);运行时,求值的结果(即装饰器函数)由下而上调用;
3、类装饰器
类装饰器在类声明的前面,类装饰器的参数是类的构造函数

@sealed
class Greeter{
    greeting:string;
    constructor(msg:string){
        this.greeting = msg;
    }
}

function sealed(constructor:Function){
    Object.seal(constructor);
    Object.seal(constructor.prototype)
}

4、方法装饰器
方法装饰器思想跟类装饰器一样。但装饰器表达式入参有三个。

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }

    @enumerable(false)
    greet() {
        return "Hello, " + this.greeting;
    }
}

function enumerable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {//第一个参数是构造函数,第二个参数是成员名字,第三个参数是成员的属性描述符
        descriptor.enumerable = value;
    };
}

5、属性装饰器

class Greeter {
    @format("Hello,%s")
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

十四、Mixins 及三斜线指令

1、ts中的mixins是一种思想,即把一个组件的代码重复组合使用。可以是引入,也可以是遍历对象或类,复制成员到目标对象。
2、三斜线指令是指在单文件包含xml标签中的最顶端的几个注释,单文件中最开头的即是注释也是指令

///<reference path="...">

十五、js文件类型检查

ts是js的超集,ts文件内书写js语法,也是允许的,且编译时会通过一定的检查及编译。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值