美文网首页
TypeScriptz学习笔记

TypeScriptz学习笔记

作者: 爱吃胡萝卜的小白兔 | 来源:发表于2020-08-09 14:42 被阅读0次

    TypeScriptz学习笔记

    标签(空格分隔): TypeScript 撩课学院


    安装TypeScript

    cnpm install -g typescript
    tsc -v  // 查看版本
    

    TypeScript初体验

    1. 类型注解

    function log(msg) {
        console.log('hello' + msg);
    }
    log('itlike');
    log(10);
    

    2. 接口

    interface Person {
        name: string,
        sex: string,
        age: number
    }
    
    function logPerson(person: Person){
        console.log(`姓名: ${person.name}, 性别: ${person.sex}, 年龄: ${person.age}`)
    }
    
    let xl = {
        name: '小撩',
        age: 25,
        sex: '女'
    }
    
    logPerson(xl);
    

    3. 类

    class Dog {
        dogName: string;
        dogAge: number;
        dogSex: string;
        
        constructor(dogName: string, dogAge: number, dogSex: string){
            this.dogName = dogName;
            this.dogAge = dogAge;
            this.dogSex = dogSex;
        }
        
        eat(foods: string){
            console.log(this.dogName + '在吃' + foods)
        }
    }
    
    let wc = new Dog('旺财', 6,'公');
    console.log(wc);
    wc.eat("蔬菜");
    

    基础类型

    1. 字符串

    let dogName: string = '旺财';
    let dogSex: string = '公';
    let dogAge: number = 5;
    
    let introDog: string = `
        我有一只小狗,它叫${dogName},
        它今年${dogAge}岁,它是
        ${dogSex}的
    `
    
    console.log(introDog);
    

    2. 数字

    // 2 8 10 16 进制
    let num1: number = 16;
    let num2: number = 0x10;
    let num3: number = 0o20;
    let num4: number = 0b10000;
    
    console.log(num1, num2, num3, num4);
    

    3. 布尔

    let flag:boolean = false;
    console.log(flag);
    

    4. 数组

    let numArr: number[] = [1,2,3];
    let strArr: string[] = ['张三', '李四', '王五'];
    console.log(numArr, strArr);
    
    let boolArr: Array<boolean> = [true, false];
    console.log(boolArr);
    

    5. 元组

    let tuple: [string, number, boolean, string];
    tuple = ['上海', 200, true, '北京'];
    console.log(tuple);
    
    let tuple1: [string, number, boolean, string] = ['上海', 200.232323, true, '北京'];
    console.log(tuple1[0]);
    console.log(tuple1[0].length);
    console.log(tuple1[1].toFixed());
    console.log(tuple1[2].valueOf());
    console.log(tuple1[3].substr(1));
    

    6. 枚举

    自动赋值

    enum Sex {
        Man,
        Women
    }
    
    let sex1: Sex = Sex.Women;
    let sex2: Sex = Sex.Man;
    console.log(sex1, sex2);
    

    手动赋值

    enum Sex {
        Man = 2,
        Women = 8
    }
    
    let sex1: Sex = Sex.Women;
    let sex2: Sex = Sex.Man;
    console.log(sex1, sex2);
    

    通过枚举的值得到名字

    enum Sex {
        Man = 2,
        Women = 8
    }
    
    let sexName: string = Sex[2];
    console.log(sexName);
    

    7. any

    let str: any;
    str = '我是小撩宝宝';
    str = 100;
    str = true;
    
    let arr: any[] = ['张三', 19, true, '男'];
    arr[3] = 2;
    console.log(arr);
    

    8. void

    // let str: void = 10; //报错
    let str1: void = null;
    let str2: void = undefined;
    
    console.log(str1, str2);
    
    function logMsg(): void {
        console.log('it like, like it');
    }
    
    logMsg();
    

    9. null和undefined

    let str1: null = null;
    let str2: undefined = undefined;
    let str3: null = undefined;
    let str4: undefined = null;
    let str5: string = null;
    let str6: string = undefined;
    
    console.log(str1, str2, str3, str4, str5, str6);
    

    10. never

    function error(msg:string): never{
        throw new Error(msg);
    }
    
    // error('发生未知错误');
    
    // 必须存在无法到达的终点
    
    function func():never {
        while(true){
            console.log(1);
        }
    }
    
    func();
    

    11. object

    object的一般使用

    let obj1:object = {name: '小撩', age: 18};
    console.log(obj1);
    console.log(obj1.toLocaleString);
    
    
    let obj = [1, 2, 3];
    console.log(obj);
    

    规定declare函数的参数必须是object

    declare function func(o: object): void
    
    func({name: '小撩'}) //OK
    func([1,2,3]) //OK
    func(null) //OK
    func(undefined) //OK
    
    func(123); //报错
    func('小撩'); //报错
    func(true); //报错
    

    12. 类型断言

    方式一:<>判断该object是string类型

    let obj: any = 'like it, it like';
    
    // let str: string = obj.substr(0, 3);
    // console.log(str);
    
    let str2: string = (<string>obj).substr(0, 3);
    let str3: string = (<string>obj).toFixed(2);
    console.log(str2);
    console.log(str3);
    

    方式二:as判断该object是string类型

    let obj: any = 'like it, it like';
    let str4: string = (obj as string).substr(0, 4);
    console.log(str4);
    

    声明和解构

    1. var和let

    // 1. var和let
    // var存在的几个问题
    // ①:仅在函数中才是块级作用域
    // ②:变量提升
    // 因此现在建议多多使用let
    
    var str:string = '撩课';
    let str1:string = 'itlike';
    
    
    // 块级作用域
    function func(flag: boolean): number{
        let a = 99;
        if(flag){
            // let b = a + 1;
            var b = a + 1;
            console.log(b);
            return b;
            
        }
        console.log(b);
        return b;
    }
    
    func(false);
    
    // 注意
    function funcA(x){
        let x = 100; //不OK,重复声明同一个变量
        var x = 100; //不OK,重复声明同一个变量
    }
    
    function funcB(flag: boolean, x:number): void {
        if(flag){
            let x = 100; //OK,因为let是块级作用域,在if里面
        }
    }
    

    2. const

    const CAT_NAME: string = "喵喵";
    // CAT_NAME = "哈哈哈"; //错误
    
    const CAT = {
        name: CAT_NAME,
        age: 8
    }
    
    console.log(CAT);
    
    // 错误
    
    // CAT = {
    //  name: '小可爱',
    //  age: 1
    // }
    
    CAT.name = "小黑黑";
    
    console.log(CAT);
    

    3. 解构

    数组的解构

    let arr:number[] = [1,2];
    let [one, two] = arr;
    console.log(one, two);
    // 交换两个变量的数值,但是这种方式不严谨,尽量少用
    [one, two] = [two, one];
    console.log(one, two);
    
    // ...符号
    let [first, ...reset] = [1, 2, 3, 4, 5];
    console.log(first); // 1
    console.log(reset); // [2, 3, 4, 5]
    

    对象的解构

    enum Sex {
        Man,
        Women
    }
    
    interface Person {
        personName: string,
        personAge: number,
        personSex: Sex
    }
    
    let person: Person = {
        personName: '小撩',
        personAge: 19,
        personSex: Sex.Women
    }
    
    let {personName, personAge, personSex} = person;
    console.log(personName, personAge, personSex);
    

    接口

    1. 接口的定义和使用

    interface Person {
        pName: string,
        pAge: number,
        pJob: string
    }
    
    // 初始化person的时候,变量的顺序是无所谓的,但是名称和类型必须和接口保持一致
    let person: Person = {
        pName: '小撩',
        pAge: 18,
        pJob: '咨询小姐姐'
    }
    
    function printPerson(person){
        console.log(`我是:${person.pName}`)
    }
    
    printPerson(person);
    

    2. 接口-可选属性

    好处:

      1. 对某些属性进行预定义
      1. 捕获错误
    // 输出接口
    interface Circle {
        color: string, // 颜色
        area: number   //面积
    }
    
    // 输入接口
    interface CircleConfig {
        // 可选属性
        color?: string,
        radius?: number
    }
    
    function createCircle(config: CircleConfig): Circle{
        let newCircle = {color: 'green', area: 100};
        if(config.color){
            newCircle.color = config.color;
        }
        if(config.radius){
            newCircle.area = Math.PI * config.radius * config.radius;
        }
        return newCircle;
    }
    
    let myCircle1 = createCircle({radius: 100});
    console.log(myCircle1);
    
    let myCircle2 = createCircle({color: 'red'});
    console.log(myCircle2);
    

    3. 只读属性

    interface FullName {
        readonly firstName: string,
        readonly lastName: string
    }
    
    let p: FullName = {firstName: '张', lastName: '三丰'};
    console.log(p);
    console.log(p.firstName, p.lastName);
    p.firstName = '李'; // 只读接口只能进行一次赋值,第二次就会报错
    console.log(p);
    console.log(p.firstName, p.lastName);
    

    只读数组

    // TS ReadonlyArray<T> Array<T>
    let arr:number[] = [1,2,3,4];
    arr.push(10);
    // arr.pop();
    console.log(arr);
    
    let ra: ReadonlyArray<number> = arr;
    // ra.push(5); //error
    // ra[0] = 10; //error
    // ra.length = 1000; //error
    console.log(ra);
    
    // 重新将ra赋值给arr,可以使用断言
    arr = ra as number[];
    console.log(arr);
    

    4. 额外的类型检查

    4.1 使用断言

    // 输出接口
    interface Circle {
        color: string, // 颜色
        area: number   //面积
    }
    
    // 输入接口
    interface CircleConfig {
        // 可选属性
        color?: string,
        radius?: number
    }
    
    function createCircle(config: CircleConfig): Circle{
        let newCircle = {color: 'green', area: 100};
        if(config.color){
            newCircle.color = config.color;
        }
        if(config.radius){
            newCircle.area = Math.PI * config.radius * config.radius;
        }
        return newCircle;
    }
    
    // 这种方式是无法给添加一个接口中没有的属性的
    // let myCircle1 = createCircle({color: 'red', radiussss: 100});
    // 1. 使用类型断言
    let myCircle1 = createCircle({color: 'red',radius: 11, radiussss: 100} as CircleConfig);
    console.log(myCircle1);
    

    4.2 通过字符串的索引签名(推荐)

    // 输出接口
    interface Circle {
        color: string, // 颜色
        area: number   //面积
    }
    
    // 输入接口
    interface CircleConfig {
        // 可选属性
        color?: string,
        radius?: number,
        // 字符串的索引签名
        [propsName: string]: any
    }
    
    function createCircle(config: CircleConfig): Circle{
        let newCircle = {color: 'green', area: 100};
        if(config.color){
            newCircle.color = config.color;
        }
        if(config.radius){
            newCircle.area = Math.PI * config.radius * config.radius;
        }
        return newCircle;
    }
    
    let myCircle1 = createCircle({color: 'red',radius: 11, radiussss: 100, a: 'q', c: 10});
    

    4.3 对象赋值

    // 输出接口
    interface Circle {
        color: string, // 颜色
        area: number   //面积
    }
    
    // 输入接口
    interface CircleConfig {
        // 可选属性
        color?: string,
        radius?: number,
    }
    
    function createCircle(config: CircleConfig): Circle{
        let newCircle = {color: 'green', area: 100};
        if(config.color){
            newCircle.color = config.color;
        }
        if(config.radius){
            newCircle.area = Math.PI * config.radius * config.radius;
        }
        return newCircle;
    }
    
    let circleOption = {color: 'red',radius: 11, radiussss: 100, a: 'q', c: 10};
    let myCircle1 = createCircle(circleOption);
    

    5. 函数类型

    interface CompareFunc {
        (first: number, last: number): boolean
    }
    
    // let myCompare: CompareFunc = function(first: number, last: number): boolean {
    //  return first > last;
    // }
    
    // let myCompare: CompareFunc = function(a: number, b: number): boolean {
    //  return a > b;
    // }
    
    let myCompare: CompareFunc = function(a, b) {
        return a > b;
    }
    
    console.log(myCompare(10,20));
    

    6. 可索引类型

    interface StrArr {
        [index: number]: string
    }
    
    let myArr:StrArr = ['it', 'like'];
    let str:String = myArr[1];
    console.log(str);
    

    7. 类类型

    7.1 属性

    interface ClockInterface{
        currentTime: Date;
    }
    
    class Clock implements ClockInterface {
        currentTime: Date;
        constructor(h: number, m: number){
            console.log(h, m);
        }
    }
    

    7.2 描述一个方法

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

    8. 类的静态部分 和 实例部分

    8.1 静态部分的类型

    interface ClockConstructor {
        new {h: number, m: number}
    }
    
    class Clock implements ClockConstructor {
        constructor(h: number, m: number){
            
        }
    }
    

    8.2 实例类型

    9. 接口继承

    interface Animal {
        // 品种
        breed: string
    }
    
    interface Cat extends Animal {
        // 颜色
        color: string
    }
    
    let cat = {} as Cat;
    cat.breed = '蓝猫';
    cat.color = '白色';
    console.log(cat);
    

    9.1 一个接口继承多个接口

    interface Animal {
        // 品种
        breed: string
    }
    
    interface Mammal {
        // 腿的数量
        leg: number
    }
    
    interface Cat extends Animal,Mammal {
        // 颜色
        color: string
    }
    
    let cat = {} as Cat;
    cat.breed = '蓝猫';
    cat.leg = 4;
    cat.color = '白色';
    console.log(cat);
    

    1. 基本使用

    var Cat = /** @class */ (function () {
        function Cat(catName) {
            this.catName = catName;
        }
        Cat.prototype.say = function () {
            return '大家好,我是: ' + this.catName;
        };
        return Cat;
    }());
    var cat = new Cat('小黑猫');
    console.log(cat);
    

    2. 继承

    class Animal{
        animalName: string;
        constructor(animalName: string){
            this.animalName = animalName;
        }
        logName(){
            return '大家好,我是: ' + this.animalName;
        }
    }
    
    class Dog extends Animal {
        // 品种
        breed: string;
        constructor(dName: string, breed: string){
            super(dName);
            this.breed = breed;
        }
        logBreed(){
            return `我的品种是${this.breed}`
        }
    }
    
    let dog = new Dog('小土豆', '土狗');
    console.log(dog);
    console.log(dog.animalName, dog.breed);
    console.log(dog.logName());
    console.log(dog.logBreed());
    

    3. 子类重写父类中的方法

    class Animal{
        name: string;
        constructor(name: string){
            this.name = name;
        }
        // 走动
        move(distance: number = 0){
            console.log(`${this.name}走动了${distance}m`)
        }
    }
    
    class Snake extends Animal {
        constructor(name: string){
            super(name);
        }
        
        // 走动
        move(distance: number = 10){
            console.log(`我是爬行的......`);
            // 调用父类的方法
            super.move(distance);
        }
    }
    
    class Horse extends Animal {
        constructor(name: string){
            super(name);
        }
        
        // 走动
        move(distance: number = 500){
            console.log(`我是飞奔的......`);
            // 调用父类的方法
            super.move(distance);
        }
    }
    
    let snake:Snake = new Snake('小青蛇');
    let horse:Animal = new Horse('白龙马');
    
    snake.move();
    horse.move(70);
    

    4. 公共、私有、受保护、只读《修饰符》

    4.1 公共的 public

    // TS成员默认都是public
    class Animal{
        public name: string;
        public constructor(name: string){
            this.name = name;
        }
        public move(distance: number = 0){
            console.log(`${this.name}走动了${distance}m`);
        }
    }
    

    4.2 私有的 private

    class Animal{
        private name: string;
        constructor(name: string){
            this.name = name;
        }
        move(distance: number = 0){
            console.log(`${this.name}走动了${distance}m`);
        }
    }
    
    let cat = new Animal('小花花');
    console.log(cat);
    cat.name = "小喵喵"; // 会报错,name属性是私有的,在实例对象中也无法使用
    cat.move(100);
    

    在TypeScript中,所有的类都是结构性的

    class Animal{
        private name: string;
        constructor(name: string){
            this.name = name;
        }
    }
    
    class Cat extends Animal{
        constructor(name: string){
            super('Cat');
        }
    }
    
    class Dog{
        private name: string;
        constructor(name: string){
            this.name = name;
        }
    }
    
    // 实例
    let animal = new Animal('猪猪');
    let cat = new Cat('小喵喵');
    let dog = new dog('dog');
    
    animal = cat;
    animal = dog;
    cat = dog;
    

    4.3 受保护的 protected

    class Person {
        protected name: string;
        constructor(name:string){
            this.name = name;
        }
    }
    
    class Employee extends Person{
        // 公司
        private company: string;
        constructor(name: string, company: string){
            super(name);
            this.company = company;
        }
        logMsg(){
            return `我叫${this.name}, 我在${this.company}工作`
        }
    }
    
    let p = new Employee('科比', 'NBA');
    console.log(p.logMsg());
    

    4.4 readonly修饰符

    // 1) 可以使用'readonly'关键字将属性设置为只读的
    // 2) 只读属性必须在声明时或构造函数里被初始化
    class Person {
        readonly name: string;
        constructor(name: string){
            this.name = name;
        }
    }
    
    let person = new Person('小撩');
    console.log(person.name);
    person.name = '大撩'; // 会报错的,readonly修饰的属性只能赋值一次
    

    5. 参数属性

    // 参数属性可以方便地让我们在一个地方定义并初始化一个成员
    // 1) 声明和赋值合并至一处
    // 2) 参数属性通过给构造函数参数前面添加一个访问限定符来声明
    class Person {
        constructor(public name: string){}
    }
    
    let p = new Person('小撩');
    p.name = '大撩';
    console.log(p.name);
    console.log(p);
    

    6. 存取器

    1. TypeScript支持通过getter/setters来截取对对象成员的访问
    2. 可以有效地控制对对象成员的访问
    注意:
    1) >= ES5
    2) 如果只实现了get, 默认就是readonly
    

    需求:先检查密码是否正确,然后再允许修改员工的信息

    // 密码:
    let passCode = 'itLike.com';
    
    class Employee {
        private _fullName: string;
        
        get fullName():string {
            return this._fullName
        }
        
        set fullName(newName:string){
            if(passCode && passCode === 'itLike.com'){
                this._fullName = newName;
            }else{
                console.log("错误: 没有权限修改用户信息!")
            }
        }
    }
    
    let p = new Employee();
    p.fullName = '科比';
    console.log(p.fullName);
    

    7. 静态属性

    1. 实例属性: 类的实例成员,仅当类被实例化的时候才会被初始化的属性
    2. 我们也可以创建类的静态成员,这些属性存在于类本身而不是类的实例上面
    class Company {
        // 静态属性
        static title = '撩课';
        // 实例属性
        constructor(public college: string){};
        // 输出
        fullName(){
            return Company.title + this.college;
        }
    }
    
    let c1 = new Company('web学院');
    console.log(c1.fullName());
    
    let c2 = new Company('Java学院');
    console.log(c2.fullName());
    

    8. 抽象类

    抽象类:

    1) 抽象类作为其它派生基类使用。
    2) 它们一般不会直接被实例化。
    3) 不同于接口,抽象类可以包含成员的实现细节。
    4) abstract 关键字是用于定义抽象类和在抽象类内部定义抽象方法
    

    抽象方法:

    1)抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
    2) 抽象方法的语法与接口方法相似,两者都是定义方法签名但不包含方法体
    3) 抽象方法必须包含abstract关键字并且可以包含访问修饰符
    
    abstract class Department {
        name: string;
        constructor(name: string){
            this.name = name;
        }
        printName():void{
            console.log('部门名称: ' + this.name);
        }
        // 抽象方法
        abstract printMetting():void // 必须在每一个继承的派生类中去实现
    }
    
    class AccountingDepartment extends Department {
        constructor(){
            super('财务部');
        }
        printMetting(): void {
            console.log('财务部每天10:00开会');
        }
        payPage():void {
            console.log('每天都发工资');
        }
    }
    
    // 约束变量的类型
    let department: Department;
    // 下面这是错误的,抽象类不能直接实例化
    // department = new Department();
    department = new AccountingDepartment();
    department.printName();
    department.printMetting();
    department.payPage(); // 错误: 方法的声明在抽象类中不存在
    

    9. 把类当作接口使用

    类定义会创建两个东西,类的实例类型和一个构造函数
    因为类可以创建出类型,所以能够在允许使用接口的地方使用类

    class Point {
        x: number;
        y: number;
    }
    
    interface Point3D extends Point{
        z: number;
    }
    
    let point3D: Point3D = {x: 10, y: 20, z: 100};
    

    函数

    1. 基本示例

    // 命名函数
    function maxA(x:number, y:number):number{
        return x > y ? x : y;
    }
    
    // 匿名函数
    let maxB = function (x:number, y:number):number{
        return x > y ? x : y;
    }
    
    // 箭头函数
    let maxC = (x: number, y: number) => {
        // this
    }
    
    let num1:number = 100;
    function func(num2, num3):number {
        return num1 + num2 + num3;
    }
    

    2. 可选参数

    TypeScript 里的每个参数都是必须的
    这不是指不能传递nullundefined作为参数,而是说编译器检查用户是否为每个参数都传入了值

    不正确的操作

    function max(x: number, y: number):number{
        return x > y ? x : y;
    }
    
    let res1 = max(10);
    let res2 = max(10, 20);
    

    正确的操作

    // 可选参数必须位于必选参数的后面
    function max(x: number, y?: number):number{
        if(y){
            return x > y ? x : y;
        }else {
            return x;
        }
    }
    
    let res1 = max(2);
    let res2 = max(2, 4);
    console.log(res1, res2);
    
    // 可以预定义一些参数的值
    function func(x: number, y = 4): void {
        console.log(x, y);
    }
    
    func(12);
    func(2, 1);
    func(2, null);
    

    3. 剩余参数

    function sum(x:number, ...resetNumber: number[]):number{
        let result:number = x;
        for(let i = 0; i < resetNumber.length; i++){
            result += resetNumber[i];
        }
        return result;
    }
    
    let result = sum(1,2,3,4,5,6);
    console.log(result);
    

    泛型

    1. 初体验

    function getNumber(num: number):number {
        return num;
    }
    
    function getNumber(num: any):any {
        return num;
    }
    
    getNumber(true);
    

    2. 泛型变量

    类型变量:它是一种特殊的变量,只用于表示类型而不是值

    function getNumber<T>(num: T):T {
        return num;
    }
    
    let r1 = getNumber<string>('一百万');
    console.log(r1);
    let r2 = getNumber<number>(10);
    console.log(r2);
    // 调用的时候,不写泛型也是可以的,这个只是方便人看
    let r3 = getNumber(true);
    console.log(r3);
    

    扩充

    function getNumber<T>(num: T):T {
        // 因为如果是number类型就没有length方法,所以错误
        console.log(num.length);
        return num;
    }
    
    // 这样就可以啦
    function getNumber<T>(num: T[]):T[] {
        console.log(num.length);
        return num;
    }
    

    3. 泛型类

    class Add<T> {
        zeroValue: T;
        add: (x:T, y:T) => T;
    }
    
    // 3.1 number类型
    let a = new Add<number>();
    a.zeroValue = 100;
    a.add(10, 20);
    
    // 3.2 其它类型
    let a = new Add<string>(){
        a.zeroValue = '2';
        a.add('200', '100');
    }
    

    4. 泛型约束

    有时候我们想去C座某类型的一组值,并且我们知道这组值具有什么样的属性
    这时,可以定义一个接口来描述约束条件

    // 创建一个包含length属性的接口
    // 通过继承这个接口,在函数调用的时候,参数必须具有length这个属性,object也可以哦
    interface LengthWise {
        length: number;
    }
    
    function getNum<T extends LengthWise>(num: T):T {
        console.log(num.length);
        return num;
    }
    
    console.log(getNum('10'));
    console.log(getNum({value:10, length: 20}));
    

    5. 在泛型约束中使用类型参数

    function getProperty<T, K extends keyof T>(obj: T, key: K){
        return obj[key];
    }
    
    let person = {name: '小撩', age: 20, sex: '女'};
    // 第二个参数,也就是key,只能是person的三个key
    let p1 = getProperty(person, 'name');
    let p2 = getProperty(person, 'age');
    let p3 = getProperty(person, 'sex');
    console.log(p1);
    console.log(p2);
    console.log(p3);
    

    类型推断

    1. TypeScript 里,在有些没有明确指出类型的地方,类型推断会帮助提供类型

    let num = 10; // 数字
    let str = '撩课'; // 字符串
    

    2. 最佳通用类型

    let arr = [0, 10, true, null] // (number | boolean | null)[]
    
    // 如果是class的话,可能不是我们希望的类型
    class Animal {
        breed: string;
    }
    
    class Dog extends Animal{};
    class Cat extends Animal{};
    
    let zoo = [new Dog(), new Cat()]; // (Dog | Cat)[],而不是我们希望的Animal[]
    // 这个时候就可以用强制类型
    let zoo:Animal[] = [new Dog(), new Cat()];
    

    3. 上下文类型

    1)TypeScript类型推断会按另外一种方式,我们称作“上下文类型”
    2)上下文类型的出现和表达式的类型以及所处的位置相关

    window.onmousedown = function(mouseEvent){
        console.log(mouseEvent.target); //OK
        console.log(mouseEvent.liaoke); //不OK
    }
    

    上下文类型会在很多情况下使用到

    1. 通常包含函数的参数,赋值表达式的右边,类型断言,对象成员,数组字面量和返回值语句
    2. 上下文类型也会作为最佳通用的候选类型
    class Animal {
        breed: string;
    }
    
    class Dog extends Animal{};
    class Cat extends Animal{};
    
    // Animal > Dog > Cat
    function createZoo(): Animal[] {
        return [new Dog(), new Cat()];
    }
    

    高级特性

    1. 联合类型:一个代码库希望传入多种类型的参数

    /*
        左侧拼接:
        1)如果传入字符串,则直接拼接
        2)如果传入数字,则创建空格拼接
        3)其它的为非法
    */
    
    // 1. 编译通过,运行报错
    function padLeft(value: string, padding: any){
        if(typeof padding === 'number'){
            return Array(padding+1).join(' ') + value;
        }
        if(typeof padding === 'string'){
            return padding + value;
        }
        throw new Error('出现错误');
    }
    
    console.log(padLeft('撩课学院', 10));
    console.log(padLeft('撩课学院', '3343434343'));
    console.log(padLeft('撩课学院', [21,32,334])); // 编译通过,运行报错
    
    // 2. 编译不通过
    function padLeft(value: string, padding: string | number){
        if(typeof padding === 'number'){
            return Array(padding+1).join(' ') + value;
        }
        if(typeof padding === 'string'){
            return padding + value;
        }
        throw new Error('出现错误');
    }
    
    console.log(padLeft('撩课学院', 10));
    console.log(padLeft('撩课学院', '3343434343'));
    console.log(padLeft('撩课学院', [21,32,334])); // 编译不通过
    

    2. 类型保护

    联合类型适用于那些值可以为不同类型的情况
    但当我们想确切地了解pet是否为Fish或者是Bird时,怎么办?

    interface Bird{
        fly();
        sleep();
    }
    
    interface Fish{
        swim();
        sleep();
    }
    
    function getSmallPet(): Fish | Bird{
        return
    }
    
    // 直接写当然是不行的
    // let pet = getSmallPet();
    // pet.sleep(); // 两种类型都有sleep方法
    // pet.swim(); // Error,比如是Fish类型才可以
    
    // 这样做,使用if else也是不行的
    // let pet = getSmallPet();
    // if(pet.swim){
    //  pet.swim();
    // }else if(pet.fly){
    //  pet.fly();
    // }
    
    // 只能通过使用断言这种方式了
    let pet = getSmallPet();
    if(pet as Fish){
        (pet as Fish).swim();
    }else{
        (pet as Bird).fly();
    }
    

    3. 自定义的类型保护

    1. 类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域里的类型
    2. 定义一个类型保护,我们只要简单地定义一个函数,它的返回值是一个类型谓词
    interface Bird{
        fly();
        sleep();
    }
    
    interface Fish{
        swim();
        sleep();
    }
    
    function getSmallPet(): Fish | Bird{
        return
    }
    
    // 谓词:p is type
    function isFish(pet:Fish | Bird): pet is Fish{
        return (pet as Fish).swim !== undefined;
    }
    
    let pet = getSmallPet();
    if(isFish){
        pet.swim();
    }else{
        pet.fly();
    }
    

    4. instanceof 类型保护

    instanceof 类型保护是通过构造函数来细化类型的一种方式

    class Bird{
        fly(){
            console.log('鸟在飞');
        };
        sleep(){
            console.log('鸟在睡');
        };
    }
    
    class Fish{
        swim(){
            console.log('鱼在游');
        };
        sleep(){
            console.log('鱼在睡');
        };
    }
    
    function getSmallPet(){
        return Math.random() > 0.5 ? new Bird() : new Fish();
    }
    
    let pet = getSmallPet();
    if(pet instanceof Bird){
        pet.fly();
    }
    
    if(pet instanceof Fish){
        pet.swim();
    }
    

    5. 可以为null的类型

    1. TypeScript具有两种特殊的类型, null和undefined,他们分别具有值null和undefined
    2. 默认情况下,类型检查器认为null与undefined可以赋值给任何类型
    3. 这就意味着:null和undefined是所有其它类型的一个有效值,这也意味着,你阻止不了
      将它们赋值给其它类型,就算是你想要阻止这种情况也不行。null的发明者,Tony Hoare,称
      它为价值亿万美金的错误

    --strictNullChecks标记可以解决此错误:当你声明一个变量时,它不会自动包含null或undefined

    let s = '撩课';
    s = null; // 错误
    console.log(s);
    let s1:string | null = 'bar';
    s1 = null;
    console.log(s1);
    s1 = undefined; // 错误
    console.log(s1);
    

    相关文章

      网友评论

          本文标题:TypeScriptz学习笔记

          本文链接:https://www.haomeiwen.com/subject/dmvldktx.html