ts类与兼容性相关

1.类
// ts和ES6区别, 需要先定义实例属性, 才能够使用实例属性
class Person {
    name:string; // 和es6的区别:需要先定义实例属性,才能够使用实例属性,如果没定义就使用会报错
    age:number;
    constructor(name:string,age:number){
        this.name = name;
        this.age = age;
    }
    say():void{
        console.log(`我的名字是${this.name}年龄是${this.age}`);
    }
    static food:string;
    static eat():void{
        console.log(this); // 当前this指向父类,所以可以调用food
        console.log(`我的食物是${this.food}`); 
    }
}
new Person('小田',22).say(); // 我的名字是小田
Person.food = '甜筒';
Person.eat(); // 我的食物是甜筒

class Student extends Person {
    book:string;
    constructor(name:string,age:number,book:string){
        super(name,age);
        this.book = book
        console.log(Student.food); // 这里是可以进行打印的,打印的是Person里的静态属性food
    }
    say():void{
        console.log(`student里的我的名字是${this.name}年龄是${this.age}${this.book}`);
    }
    static sayfood():void{
		console.log(this.food)
    }
}
Student.food = 'dwadwadwa';
Student.sayfood();
2.类属性修饰符
// public(公开的)      :
// 如果使用public来修饰属性, 那么表示这个属性是公开的
// 可以在类的内部使用, 也可以在子类中使用, 也可以在外部使用

// protected(受保护的) :
// 如果使用protected来修饰属性, 那么表示这个属性是受保护的
// 可以在类的内部使用, 也可以在子类中使用

// private(私有的)     :
// 如果使用private来修饰属性, 那么表示这个属性是私有的
// 可以在类的内部使用

// readonly(只读的)    :
class Person {
    public name:string; // 默认情况下就是public的
    protected age:number;
    private gender:string;
    constructor(name:string, age:number, gender:string){
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    say():void{
        console.log(`name=${this.name},age=${this.age},gender=${this.gender}`);
    }
}
class Student extends Person{
    constructor(name:string, age:number, gender:string){
       super(name,age,gender);
    }
    say():void{
        // console.log(`name=${this.name}`); // name=xt
        // console.log(`age=${this.age}`); // age=11
        // console.log(`gender=${this.gender}`); // Error 私有的属性,继承不可以访问
    }
}
let p = new Student('xt',11, '1');
p.say();
3.类只读属性
//  类的只读属性:
//          可以在constructor内赋值多次,但是不能在实例的方法中更改值,也不能在外部实例中更改属性
class Person {
    readonly name:string;
    constructor(name:string){
        this.name = name;
        this.name =' 11111';
    }
}

let p = new Person('dwadw');
console.log(p.name);
// p.name ='dwadwadwa'; // 无法分配到 "name" ,因为它是只读属性。

4.类方法修饰符
class Person {
    name:string;
    age:string;
    gender:string;
    constructor(name:string,age:string,gender:string){
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    public sayName():void{
        console.log(`person我的名字是${this.name}`);
    }
    protected sayAge():void{
        console.log(`person我的年龄是${this.age}`);
    }
    private sayGender():void{
        console.log(`person我的性别是${this.gender}`);
    }
}

class Student extends Person{
    constructor(name:string,age:string,gender:string){
        super(name,age,gender);
    }
    say():void{
        // this.sayName(); // person我的名字是小田
        // this.sayAge(); // person我的年龄是22
        this.sayGender(); // 属性“sayGender”为私有属性,只能在类“Person”中访问。ts(2341)
    }
}
let p = new Student('小田','22','男');
let p1 = new Person('111', '34', '1');
p.say();
p1.sayName();
p1.sayAge(); // 属性“sayAge”受保护,只能在类“Person”及其子类中访问。ts(2445)
p1.sayGender(); // 属性“sayGender”为私有属性,只能在类“Person”中访问。ts(2341)


5.类可选参数
// 类可选属性
// 和接口的可选属性一样,可传可不传的属性
// 注意:
//      1.如果在类中,定义属性时,如果只定义了类型,没有初始化值,那么在constructor中必须赋值,不然会报错
//      2.如果定义属性时,初始化值,就不用在构造器中使用赋值,不会报错
class Person {
    name:string;
    age?:string;
    constructor(name:string,age?:string){
        this.name = name;
        this.age = age;
    }
    setname(name:string,age:string):void{
        this.name = name;
        this.age = age;
    }
}

let p = new Person('laotianwy'); // Person { name: 'laotianwy', age: undefined }
p.setname('xiaotian','23'); // Person { name: 'xiaotian', age: '23' }

// 需求: 有一个基类, 所有的子类都需要继承于这个基类, 但是我们不希望别人能够通过基类来创建对象
class Person {
    name:string;
    age:number;
    gender:number;
    protected constructor(name:string,age:number,gender:number){
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    say():void{
        console.log(`我的名字是${this.name},我的年龄是${this.age},我的性别是${this.gender}`);
    }
}

class Student extends Person{
    constructor(name:string,age:number,gender:number){
        super(name,age,gender);
    }
}

let p = new Person('name',11,22); // Error
let p1 = new Student('name',11,22);

6.类构造器参数使用public
// 如果在constructor中参数使用了public修饰,那么就不用在声明实例属性了
class Student {
    constructor(public name:string,public age:string){

    }
}
new Student('xxxxxxx','22222'); // Student { name: 'xxxxxxx', age: '22222' }
7.类的可选属性
//  类可选属性
//  和接口的可选属性一样,可传可不传 在实例属性内加 ? 
class Person {
    name:string;
    age?:number;
    constructor(name:string,age?:number){
        this.name = name;
        this.age = age;
    }
}
new Person('laotian');

class Student {
    constructor(public name:string,public age?:number){

    }
}
let p = new Student('laitan'); // Student { name: 'laitan', age: undefined }
8.存储器
//  存储器
// 通过getters/setters来截取对对象成员的访问
class Person {
    _age:number = 0;
    private _name:number = 0;
    set age(val:number){
        console.log(val);
        if(val < 0 ){
            throw new Error('人的年龄不能小于0');
        }
        this._age = val;
    }
    get age():number{
        console.log('进入了get age 的方法');
        return this._age;
    }
    set name(val:number){
        console.log(val,'name');
        this._age = val;
    }
    get name():number{
        return this._name;
    }
}

let p = new Person();
p.age = 42; // p.age(42)
console.log(p.age); // p.age();
9.抽象类
// 抽象类
//  1.抽象类专门用于定义那些不希望被外界直接创建的类
//  2.抽象类一般用于定义基类
//  3.抽象类和接口一般用于约束子类
//  4.区别:
//      1.接口中只能定义约束,不能定义具体实现
//      2.抽象类即可以定义约束,又可以定义具体实现
//      3.抽象类不能创建实例,
//      4.抽象类的属性如果是abstract修饰,那么不能够继承,只能再次在子类中再次声明

abstract class Person1{
    abstract name:string;
    abstract say():void;
    eat():void{
        console.log(`${this.name}正在吃饭`);
    }
}
// let p1 = new Person1(); // Error 无法创建抽象类的实例。ts(2511)

// 非抽象类“Student1”不会实现继承自“Person1”类的抽象成员“name”。ts(2515)
// 非抽象类“Student1”不会实现继承自“Person1”类的抽象成员“say”。ts(2515)
class Student1 extends Person1{
    name:string = 'xiaotian';
    say():void{
        console.log(`我的名字是${this.name}`)
    }
}

let ab1 = new Student1();
ab1.say(); // 我的名字是xiaotian
ab1.eat(); // xiaotian正在吃饭
10.类与接口
//  类和接口
//  1.类 实现 接口:使用implements关键字实现
//                 只要实现某一个接口,那么就必须实现接口当中所有的属性和方法
interface PersonFace{
    name:string;
    say():void;
}

class Person implements PersonFace {
    name:string;
    constructor(name:string) {
        this.name = name;
    }
    say():void{

    }
}


//  2.接口继承类
//      1.只要这个接口继承了某个类,那么就会继承这个类的所有的属性和方法
//      2.但是只会继承属性和方法的声明,不会继承属性和方法的实现
//      注意:如果接口继承的类中包含了protected的属性和方法,那么就只有这个类的子类才能实现这个接口

class Honey {
    name:string = 'xt';
    age:number = 22;
    say():void{
        console.log(`我的名字是${this.name}年龄是${this.age}`);
    }
}
interface PersonHoneyInterface extends Honey{
    gender:string;
}

// 第一种方式类实现接口
class StudentHoney implements PersonHoneyInterface {
    name:string = 'xiaotian';
    age:number = 21;
    gender:string = 'nan';
    say():void{
        console.log(`大娃大娃多哇我`);
    }
}

// 第二种方式类实现接口
class StudentHoney1 extends Honey implements PersonHoneyInterface {
    gender:string = 'dwadwa'; // 如果没有gender属性会报错
}

let stu1 = new StudentHoney1(); //  如果 "StudentHoney1" 中缺少属性 "gender",但类型 "PersonHoneyInterface" 中需要该属性。就会Error
console.log(stu1);
11.类和泛型
//  类和泛型
//  泛型类
class Student<t> {
    arr:t[] = [];
    add(values:t):void{
        this.arr.push(values);
    }
    all():t[]{
        return this.arr;
    }
}

let initStudent = new Student<number>();
initStudent.add(1);
initStudent.add(2);
initStudent.add(3);
initStudent.all(); // [ 1, 2, 3 ]
12.同名接口合并现象
//  接口合并现象
//  当我们定义了多个同名的接口,多个接口的内容会自动合并
//  如果使用类实现的话那么就得全部实现,要不然会报错
interface TestFace{
    name:string;
}
interface TestFace{
    age:number;
}
interface TestFace{
    gender:boolean;
}

// 如果实现的话那么就得全部实现 要不然会报错
class Person implements TestFace{
    name:string = 'dwadw';
    age:number = 2123;
    gender:boolean = true;
}
13.枚举-字符串枚举和数字枚举
//  数字枚举和字符串枚举
//  1.数字枚举
//      1.数字枚举默认从0开始,数字枚举的取值可以是字面量也可以是常量,也可以是结算的结果
//      2.如果使用常量给前面的枚举赋值了,那么后面的枚举值也需要手动的赋值
//      3.如果使用计算结果给前面的枚举赋值,那么后面的枚举值也需要手动的赋值
//      注意:如果使用了常量或者计算属性那么是可以通过索引进行获取枚举的
//  2.字符串枚举值
//      1.如果使用字符串枚举值给前面的枚举值赋值了,那么后面的枚举值也必须手动赋值
//      2.和数字枚举不一样,字符串枚举不能使用常量和计算属性给枚举赋值
//      3.虽然字符串枚举不能够使用常量或者计算属性赋值,但是可以使用内部的其他枚举来赋值
//      注意:如果使用了字符串枚举那么就不能通过索引进行获取了

enum Gender{
    Male,
    Female
}
console.log(Gender.Male);  // 0
console.log(Gender.Female); // 1
//  2.数字枚举注意点:
//      1.数字枚举默认从0开始,数字枚举的取值可以是字面量也可以是常量,也可以是结算的结果
//      2.如果使用常量给前面的枚举赋值了,那么后面的枚举值也需要手动的赋值
//      3.如果使用计算结果给前面的枚举赋值,那么后面的枚举值也需要手动的赋值
//      注意:如果使用了常量或者计算属性那么是可以通过索引进行获取枚举的
const num = 55;
function getNum(){
    return 999;
}
enum SexList{
    // male = 6,
    man = num,
    female = getNum()
}

console.log(SexList.man); // 55
console.log(SexList[55]); // male
console.log(SexList.female); // 999

//  3.枚举反向映射
//      1.可以根据枚举值获取到原始值
//      2.也可以根据原始值获取到枚举值
enum gender1{
    male,
    female
}

console.log(gender1.male); // 0
console.log(gender1[0]); // male

//  3.字符串枚举值
//      1.如果使用字符串枚举值给前面的枚举值赋值了,那么后面的枚举值也必须手动赋值
//      2.和数字枚举不一样,字符串枚举不能使用常量和计算属性给枚举赋值
//      3.虽然字符串枚举不能够使用常量或者计算属性赋值,但是可以使用内部的其他枚举来赋值
//      注意:如果使用了字符串枚举那么就不能通过索引进行获取了
const str1 = 'laotian';
function getStr(){
    return 'abc;'
}
enum gender2{
    // male= 'www.baidu.com',
    // male = str1, // Error
    // male = getStr() // Error
    female = 'www.xinlang.com',
    yao = female
}

console.log(gender2.female); // www.xinlang.com
console.log(gender2.yao); // www.xinlang.com
// console.log(gender2['www.xinlang.com']); // 如果使用了字符串枚举那么就不能通过索引进行获取了

14.枚举成员类型和联合类型
// 枚举成员类型
//      1.可以把枚举成员当做类型使用
enum Gender{
    male = 'www.baidu.com',
    female = 'www.laotian.com',
}
interface TestInterface{
    age:Gender.male
}
class Person implements TestInterface{
    // age:Gender.male = Gender.male;
    // age:Gender.female; // Error类型不匹配报错
    // age:Gender.male = 0; //  Error不能将类型“0”分配给类型“Gender.male”。原因是枚举值是字符串,如果枚举值是数字那么就可以进行赋值是0
    age:Gender.male = Gender.male;
    // age:Gender.male = 'dwadwa'; // Error 如果是字符串枚举,只能赋值枚举成员的值,上面就不会报错
    age:Gender.male = true; // Error 如果赋值别的值,会报错
}

//  2.联合枚举类型
//      1.什么是联合类型
//          联合数据类型就是将多种数据类型通过|链接起来
//          可以把枚举类型当做一个联合类型来使用
let value:(number|string); // (number|string)联合类型,既可以存数字又可以存字符串
enum Gender1 {
    Male,
    Female
}
interface testInterface{
    age:Gender1 // age:(Gender1.Male|Gebder1.Female)
}

class Person1 implements testInterface {
    // age = 0; 
    // age = Gender1.Male;
    age = Gender1.Female;
}
15.运行时枚举
// 运行时枚举
//  1.枚举在编译后是一个真实存储的对象,所以可以在运行时使用
//  2.而像接口这种只是用来约束做静态检查的代码,编译之后是不存在的
interface TestInterface{
    name:string;
    age:number;
}
enum Gender{
    male,
    female
}

// 常量枚举
//  1.普通枚举和常量枚举的区别
//      1.普通枚举会生成真实存在的对象
//      2.常量枚举不会生成真实存在的对象,而是利用枚举成员的值直接替换使用到的地方
var Gender1;
(
    function(Gender1){
        Gender1[Gender1['male'] = 0] = 'male';
        Gender1[Gender1['female'] = 1] = 'female';
    }
)(Gender1 || (Gender1 = {}))

enum Gender100{
    male,
    female
}
console.log(Gender100.male === 0);// true

const enum Gender200{
    male,
    female
}

console.log(Gender200.male === 0); // true
16.类型推断
// 类型推断
//  1.什么是类型推断
//      1.不用明确告诉编译器是什么类型,编译器就知道是什么类型
//  2.根据初始化值自动推断
//      1.如果是先定义再初始化,那么是无法自动推断的
//      2.如果是定义的同时初始化,那么ts就会自动进行类型推断
//  3.根据上下文类型自动推断
//  4.推荐一篇文章:https://blog.csdn.net/u011127019/article/details/73867203?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162167388616780366515120%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162167388616780366515120&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-1-73867203.pc_search_result_hbase_insert&utm_term=typescript+%E4%BB%80%E4%B9%88%E6%98%AF%E5%85%BC%E5%AE%B9%E6%80%A7&spm=1018.2226.3001.4187
let values;
values = 2222;
values = 'dwadwa';

let values1 = 2132;
// values1 = 'dwadwad'; // Error

let arr1 = [1,'a']; // (number|string)[]
// arr1 = ['dwafaw',2123,'dwadw',true] // Error 前面的没事,最后一个true有问题 不能将类型“boolean”分配给类型“string | number”。ts(2322)

// 根据上下文类型类型自动推断
window.onmousedown = (event) => {
    console.log(event.target);
}

17.类型兼容性
// 类型兼容性
//  1.基本兼容性,interface与变量兼容
interface TestInterface{
    name:string
}
let p1 = {name:'laotian'};
let p2 = {age:22};
let p3 = {name:'laotian',age:22};

let t:TestInterface;
t = p1;
t = p2; // Error
t = p3; // 可多不可少


interface Test1Interface{
    name:string;
    children:{
        age:number
    }
}

let p4 = {name:'laotian',children:{age:22}}
let p5 = {name:'laotian',children:{age:'age'}}
let t2:Test1Interface;
t2 = p4;
t2 = p5; // Error 会递归检查,age是字符串类型
18.函数兼容性
//  函数兼容性:可以把少的赋值给多的,
// 参数个数
let fn1 = (x:number,y:number) => {};
let fn2 = (x:number) => {};
fn1 = fn2;
// fn2 = fn1; // Error  会报错 不能将类型“(x: number, y: number) => void”分配给类型“(x: number) => void”。ts(2322)

// 参数类型:必须一模一样
let f1 = (x:number) => {};
let f2 = (x:number) => {};
let f3 = (x:string) => {};
f1 = f2;
// f1 = f3; // Error 类型必须一样 不能将类型“(x: string) => void”分配给类型“(x: number) => void”。参数“x”和“x” 的类型不兼容。不能将类型“number”分配给类型“string”。
f2 = f1;

// 返回值类型:返回的类型必须一样
let t1 = ():number => 123;
let t2 = ():number => 123;
let t3 = ():string => '123';

t1 = t2;
t2 = t1;
// t1 = t3; // Error 返回的类型必须一样

// 函数的双向斜变
//  1.参数的双向斜变
let change1 = (x:(number|string)) => {};
let change2 = (x:number) => {};
change1 = change2; // 不能将类型“(x: number) => void”分配给类型“(x: (number | string)) => void”。参数“x”和“x” 的类型不兼容。不能将类型“string | number”分配给类型“number”。 不能将类型“string”分配给类型“number”。
change2 = change1;

//  2.返回值双向斜变
//      1.可以将返回值是具体类型的赋值给联合类型的
//      2.不能将返回值是联合类型的赋值给具体类型的
let return1 = (x:boolean):(number|string) => x ? 123:'123';
let return2 = (x:boolean):number => 456;
return1 = return2; // 可以将返回值是具体类型的赋值给联合类型的
return2 = return1; // 不能将返回值是联合类型的赋值给具体类型的

//  函数的重载
//      1.不能讲重载少的,赋值给重载多的,
//      2.可以将重载多的,赋值给重载少的
function add(x:number,y:number):number;
function add(x:string,y:string):string;
function add(x,y){
    return x+y;
}
function sub(x:number,y:number):number;
function sub(x,y):number{
    return x-y;
}
let add1 = add;
let sub1 = sub;
add1 = sub1; // 不能将类型“(x: number, y: number) => number”分配给类型“{ (x: number, y: number): number; (x: string, y: string): string; }”。参数“x”和“x” 的类型不兼容。不能将类型“string”分配给类型“number”。
sub1 = add1;
19.枚举兼容性
//  枚举兼容性
//      1.数字枚举和数字枚举兼容
//      2.数字枚举和数字枚举不兼容,不能兼容别的枚举
//      3.字符串枚举和字符串不兼容
// 数字枚举和数字枚举兼容
enum Gender{
    male,
    female
}
let value:Gender;
value = Gender.male;
value = 0;

// 数字枚举和数字枚举不兼容

enum Gender1{
    male,
    female
}

enum Gender2{
    male,
    female
}

let val1:Gender1;
val1 = Gender1.male;
// val1 = Gender2.male; // Error 不能将类型“Gender2.male”分配给类型“Gender1”。ts(2322)

// 字符串枚举和字符串不兼容
enum StringEnum{
    male = 'abc',
    female = 'def'
}

let valueStr:StringEnum;
valueStr = StringEnum.male;
valueStr = 'abc'; // Error 不能将类型“"abc"”分配给类型“StringEnum”。ts(2322)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值