typescript

typescript

说明

typescript是javascript的超集。
ts文件中如果只有正常的js代码,可以再谷歌浏览器直接引入,否则需要先解析为js文件再引入js文件。
typescript的核心原则之一是对值所具有的结构进行类型检查。

一.安装

npm install -g typescript

检验命令

tsc -v

二.编译

tsc myTs.ts

编译结果

myTs.js

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6IfuHvn8-1673689252920)(img.png)]

编译前后区别

js文件中,没有形参定义的类型;
ts中使用的let编译为var。

配置自动编译ts文件

tsc --init

生成 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yYRF4B0f-1673689252922)(img_1.png)]文件
这里我用的webstorm
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jNoD4GgS-1673689252922)(img_2.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QjOBAVRZ-1673689252922)(img_3.png)]
配置之后,自动编译生效

语法

一.类型注解

一种轻量级的为函数或变量添加的约束

(function () {
    function sayHi(str: String) {
        return "hello" + str;
    }
    let str = "花花";
    let arr = [1, 2, 3];
    console.log(sayHi(str));
    // console.log(sayHi(arr)) // 这里会报错,arr是Object类型
})()

二.接口

接口是对对象的状态(属性)和行为(方法)的抽象(描述),是一种对实例的约束。

1.实例的属性和方法是否和定义的一致
2.变量名前可以使用readonly设置只读
3.变量名后可以使用?表示非必须
(function () {
    interface IPerson {
        readonly id: number,
        firstName: string,
        lastName: string,
        age?: number
    }
    class Person {
        firstName: string
        lastName: string
        fullName: string

        constructor (firstName: string, lastName: string) {
            this.firstName = firstName;
            this.lastName = lastName;
            this.fullName = this.firstName + " " + this.lastName;
        }
    }

    function showFullName(person: IPerson) {
        return person.firstName + " " + person.lastName;
    }

    const person = new Person("张", "三")
    // const person = new Person("张")  这里会报错,不符合类形参的规范
    console.log(showFullName(person));
    // Argument of type 'Person' is not assignable to parameter of type 'IPerson'.
    // Property 'id' is missing in type 'Person' but required in type 'IPerson'.
    person.id = 12;
    // Property 'id' does not exist on type 'Person'.
})()

三.基本类型

变量定义好的类型不能重新赋值为其他类型。

Boolean, String, Number
let a: boolean = true; // Boolean类型
let b: string = "张三"; // String类型
let c: number = 12; // Number类型
// a = 13 报错
undefined, null

undefined和null都可以作为其他类型的子类型(非严格模式下)

let und: undefined = undefined;
let nul: null = null;
let num: number = undefined;
let str: string = null;
console.log(und, nul, num, str);
数组
// 第一种
// let arr: number[] = [1, 32, 543];
let arr: number[] = [1, 2, 4, ""];
// 第二种(泛型)
// let arr2: Array<number> = [2, 5, 7]

数组中数据类型不正确会报错,数据类型必须和定义的是一致的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FYpUl4Bv-1673689252923)(img_4.png)]

元组

元组类型:数据的类型、位置、个数都要和定义的保持一致。

let arr3: [String, Number, Boolean] = ["张三", 12, false];

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GiAAjBe6-1673689252923)(img_5.png)]

枚举

枚举是对javascript标准数据类型的补充,
枚举中的每个数据值都可以叫元素,每个元素都有自己的编号,默认递增(类似下标)。
枚举中的元素可以通过编号获取名字。

enum Color {
    red,
    blue,
    green
}
let color: Color = Color.red;
enum Color2 {
    red = 2,
    blue = 4,
    green = 7
}
let color2: Color2 = Color2.red;
let color3: string = Color[1];
console.log(color, color2, color3)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OWBnH2Qo-1673689252923)(img_8.png)]

any类型

当数组中类型、个数、位置都不确定时,可以用any类型

let str1: any = 100;
str1 = "张三"
let arr4: any[] = [123, "z行三", true];
console.log(str1, arr4)
void类型

表示函数没有返回值

function showMsg(): void {
    console.log("void表示没有返回值");
    // return;
    // return undefined;
    // return null
    return 123
}
console.log(showMsg());

上面代码中依次打印undefined, undefined, null, 123,但是123时编辑器中会有错误提示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zPxPU1Sg-1673689252923)(img_9.png)]

let vd: void = undefined;
// 表示生命一个void类型的数据,意义不大。
object类型
function getObj(obj: object):object {
    console.log(obj);
    return {
        name: "zhangsan",
        age: 12
    }
}
console.log(getObj({}))
console.log(getObj(new String("123")))
联合类型

联合类型表示取值可以为多种类型中的有一种

function getString(str: number|string):string {
    // return str; 这里会报错,因为返回值时string。
    return str.toString()
}
console.log(getString(123));
console.log(getString("123"));
类型断言

1.<类型>变量名
2.变量名 as 类型
当我们不确定变量具体的类型时,可以使用类型断言指定为我们指定的数据类型

function getStrFn(x: string|number):number {
    if ((<string>x).length) {
        return (x as string).length;
    } else {
        return x.toString().length;
    }
}
console.log(getStrFn(123));
console.log(getStrFn("423"));
类型推断

在typescript中,定义变量时,没有明确的指定类型时,将会根据赋值推测出一个类型,没有赋值即为any

函数类型

为了使用接口表示函数类型,我们需要给接口定义一个调用签名。
它就像一个只有参数列表和返回值累心通过的函数定义,参数列表里的每个参数都需要名字和类型。

(function () {
    // 这里定义了两个参数及它们的类型,还有返回值的类型
    interface ISearchFunc {
        (source: string, substr: string): boolean
    }
    // 使用了定义好的接口来规范函数
    const searchFunc: ISearchFunc = function (source: string, substr: string): boolean {
         return source.search(substr) > -1;
    }
    console.log(searchFunc("今天你做核酸了吗", "吃"));
    console.log(searchFunc("今天你做核酸了吗", "核酸"));
})()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-13MfcQtw-1673689252924)(img_10.png)]

类类型

定义一个类,这个类的类型是定义好的接口。
类可以实现多个接口,接口中的内容给必须要实现。

(function () {
    interface IFly {
        fly();
    }
    interface ISwim {
        swim();
    }
    // 这里继承了两个接口
    class Person implements IFly, ISwim  {
        fly () {
            console.log("fly");
        }
        swim () {
            console.log("swim");
        }
    }
    const person = new Person();
    person.fly();
    person.swim();
})()
扩展:接口可以继承多个接口
  // 扩展:接口可以继承多个接口
interface FlyAndSwim extends IFly, ISwim { };
class Person2 implements FlyAndSwim {
    fly () {
        console.log("fly2");
    }
    swim () {
        console.log("swim2");
    }
}
const person2 = new Person2();
person2.fly();
person2.swim();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IGCbrXbF-1673689252924)(img_11.png)]

总结:接口继承接口(extends),类实现接口(implements)。

可以理解为模板,通过模板可以实例化对象(面向对象)。

(function () {
    class Person {
        readonly id: number
        name: string
        age: number
        sex?: string
        
        constructor(id: number, name: string, age: number, sex?: string) {
            console.log(`id是${id}的人叫${name},今年${age}岁,性别${sex ? sex : "不明"}`)
        }
    }
    const person = new Person(0, "张三", 18);
})()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ES5I8Kw-1673689252924)(img_12.png)]

继承

类和类可以实现继承,使用extends。
子类可以调用父类的构造函数和实例方法,使用super关键字。
子类可以重写父类的实例方法。

(function () {
    class Father {
        name: string
        age: number
        constructor(name: string, age: number) {
            this.name = name;
            this.age = age
        }
        sayHi(str: string) {
            console.log(`我是${this.name}${str}`)
        }
    }
    class Children extends Father {
        constructor(name: string, age: number) {
            super(name, age);
        }
        sayHi() {
            super.sayHi("我是子类")
        }
    }
    const father = new Father("father", 40);
    const child = new Children("child", 12);
    father.sayHi("我是父类");
    child.sayHi();
})()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wNKOGIOS-1673689252924)(img_13.png)]

多态

父类型的引用指向了子类型的对象,不同类型的对象引用相同的方法,产生了不同的行为。

(function () {
    class Father {
        name: string
        constructor (name: string) {
            this.name = name;
        }
        sayHi () {
            console.log(`I am ${this.name}`);
        }
    }

    class Child1 extends Father {
        hobby: string
        constructor(name: string, hobby: string) {
            super(name);
            this.hobby = hobby;
        }
        sayHi () {
            super.sayHi();
            console.log(`I like ${this.hobby}`);
        }
    }

    class Child2 extends Father {
        sport: string
        constructor(name: string, sport: string) {
            super(name);
            this.sport = sport;
        }
        sayHi() {
            console.log(`I am ${this.name}, I like ${this.sport}`)
        }
    }
    const father = new Father("张三");
    const child = new Child1("张三的大儿子", "computer games");
    const child2 = new Child2("张三的二儿子", "basketball");
    father.sayHi();
    child.sayHi();
    child2.sayHi();

    function run (one: Father) {
        one.sayHi();
    }
    run(child)
})()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CZaUyO3y-1673689252925)(img_14.png)]

默认,私有与受保护的修饰符

public

可以自由的访问程序里定义的成员,默认是public
先来声明一个基本的类

class Person {
    // 属性
    name: string;
    // 构造函数
    constructor(name: string) {
        this.name = name;
    }
    // 方法
    eat() {
        console.log('吃')
    }
}
const per = new Person('狗蛋');
console.log(per.name);
per.eat();

在这里插入图片描述

这里per.name及per.eat都可以访问,可以看作是:

class Person {
    // 属性
    public name: string;
    // 构造函数
    public constructor(name: string) {
        this.name = name;
    }
    // 方法
    public eat() {
        console.log('吃')
    }
}
const per = new Person('狗蛋');
console.log(per.name);
per.eat();

我们把name属性为私有属性

private

不能在声明它的类的外部访问

class Person {
    // 属性
    private name: string;
    // 构造函数
    public constructor(name: string) {
        this.name = name;
    }
    // 方法
    public eat() {
        console.log('吃')
    }
}
const per = new Person('狗蛋');
console.log(per.name);
per.eat();

在这里插入图片描述
访问name出现了报错
接下来验证子类继承父类后,是否可以访问私有变量。

class Person {
    // 属性
    private name: string;
    // 构造函数
    public constructor(name: string) {
        this.name = name;
    }
    // 方法
    public eat() {
        console.log('吃')
    }
}
const per = new Person('狗蛋');
console.log(per.name);
per.eat();

class Student extends Person {
    constructor(name: string) {
        super(name);
    }
    show() {
        console.log("我的名字是" + this.name);
    }
}

这里子类不可以访问父类的私有属性
在这里插入图片描述

protected

与private修饰符的行为相似,但是protected成员在派生类中仍然可以访问。

在外部访问protected修饰的属性

class Person {
    // 属性
    protected name: string;
    // 构造函数
    public constructor(name: string) {
        this.name = name;
    }
    // 方法
    public eat() {
        console.log('吃')
    }
}
const per = new Person('狗蛋');
console.log(per.name);
per.eat();

类的外部不可以访问protected修饰的变量

子类访问父类proteced修饰的属性

class Person {
    // 属性
    protected name: string;
    // 构造函数
    public constructor(name: string) {
        this.name = name;
    }
    // 方法
    public eat() {
        console.log('吃')
    }
}
// const per = new Person('狗蛋');
// per.eat();
class Student extends Person {
    constructor(name: string) {
        super(name);
    }
    show() {
        console.log("我的名字是" + this.name);
    }
}
const per = new Student('狗蛋');
per.show()

子类可以访问父类protected修饰的属性。
在这里插入图片描述

readonly修饰符

readonly是一个关键字,对类中的属性成员进行修饰,修饰后,该属性成员就不能在外部被随意的修改了。

1.构造函数中,可以对只读的属性成员的数据进行修改,普通方法不可以修改;
2.如果构造函数中没有任何参数,类中的属性成员此时已经使用readonly进行修饰了,那么外部也不能对这个属性值进行更改的
3.构造函数的参数可以使用readonly进行修饰,一旦修饰了,那么该类中就有了这个只读的成员属性,这里叫做参数属性,外部可以访问,但是不能修改
4.构造函数中的参数可以使用public及private和proteced进行修饰,类中会自动添加这个属性成员。

接下来我们通过代码逐条进行验证
1.构造函数修改只读数据

class Person {
    readonly name: string = "张三";
    constructor(name: string) {
        this.name = name;
    }
}
const per = new Person("李四");
console.log(per.name);

那么如果是类中的普通方法呢

class Person {
    readonly name: string = "张三";
    constructor(name: string) {
        this.name = name;
    }
    changeName() {
        this.name = "王五"
    }
}
const per = new Person("李四");
console.log(per.name);

在这里插入图片描述

2.无参数时,从外部修改readonly修饰的属性。

class Person {
    readonly name: string = "张三";
    constructor() {}
}
const per = new Person();
per.name = "李四"

在这里插入图片描述
3.readonly修饰构造函数的参数
先看一段代码

class Person {
    readonly name: string = "张三";
    constructor(readonly name: string) {
        this.name = name;
    }
}

在这里插入图片描述
这里就是上面所说,一旦使用readonly修饰了构造函数的参数,类中就自动添加了对应的成员属性。

readonly修饰参数,可以正常访问

class Person {
    constructor(readonly name: string) {
        this.name = name;
    }
    show() {
        console.log(this.name);
    }
}
const per = new Person("王五");
per.show();

外部不能修改

class Person {
    constructor(readonly name: string) {
        this.name = name;
    }
    show() {
        console.log(this.name);
    }
}
const per = new Person("王五");
per.name = "赵六"
per.show();

在这里插入图片描述
4.public、private、protected修饰,类中自动添加成员属性

class Person {
    private name: string;
    constructor(private name: string) {
        this.name = name;
    }
}
const per = new Person("王五");

在这里插入图片描述

存取器

让我们可以有效的控制对对象成员的访问,通过getters和setters进行操作

class Person {
    firstName: string;
    lastName: string;
    constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    get fullName() {
        console.log("调用了get");
        return this.firstName + "_" + this.lastName;
    }

    set fullName(val: string) {
        console.log("调用了set");
        this.firstName = val.split("_")[0];
        this.lastName = val.split("_")[1];
    }
}
const per = new Person("上官", "老大");
console.log(per.fullName);

在这里插入图片描述

	按照结果我们可以看到:
	1.per对象是拥有fullName的;
	2.在 访问fullName时,调用了get
class Person {
    firstName: string;
    lastName: string;
    constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    get fullName() {
        console.log("调用了get");
        return this.firstName + "_" + this.lastName;
    }

    set fullName(val: string) {
        console.log("调用了set");
        this.firstName = val.split("_")[0];
        this.lastName = val.split("_")[1];
    }
}
const per = new Person("上官", "老大");
per.fullName = "上官_老二";

在这里插入图片描述
这里表明,设置firstName和lastName,我们可以使用构造函数的方式,也可以使用set的方式。

静态成员

在类中通过static修饰的属性或方法称为静态成员

class Person {
    name: string
    static age: number
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    show() {
        console.log(this.name);
    }
}

在这里插入图片描述
age是静态属性,不能使用this.或实例对象去调用;

(function () {
    class Person {
        name: string
        static age: number = 12;
        constructor(name: string) {
            this.name = name;
        }
        show() {
            console.log(this.name);
        }
    }
    const per: Person = new Person("张三");
    console.log(per);
    console.log(Person.age); // 通过类名访问该成员数据
})()

在这里插入图片描述

构造函数不能使用static进行修饰。

抽象类

抽象类为子类服务。
抽象类包含抽象方法,也可以包含实例方法。

(() => {
    abstract class Animal {
        abstract eat() {

        }
        move() {

        }
    }
})()

在这里插入图片描述
1.抽象方法一般没有任何具体内容的实现。

正确的写法如下

(() => {
    abstract class Animal {
        abstract eat() ;
        move() {

        }
    }
})()

2.抽象类不能被实例化。

(() => {
    abstract class Animal {
        abstract eat()
        move() {

        }
    }
    const ani = new Animal();
})()

在这里插入图片描述
3.继承抽象类必须实现抽象方法

(() => {
    abstract class Animal {
        abstract eat()
        move() {

        }
    }
    class Person extends Animal {

    }
})()

在这里插入图片描述

(() => {
    abstract class Animal {
        abstract eat()
        move() {

        }
    }
    class Person extends Animal {
        eat() {
            console.log("吃熟食");
        }
    }
    const per = new Person();
    per.eat();
})()

函数

ts的函数可以指定参数数据类型和函数的返回值类型

(() => {
    // 函数式声明
    function add(x: number, y: number): number {
        return x + y;
    }
    // 表达式声明
    const minus = function (x: number, y: number): number {
        return x - y;
    }

})()

函数的完成写法

// 相当于函数add2要符合function (x: number, y: number):number { return x + y }的格式
const add2: (x: number, y: number) => number = function(x: number, y: number): number {
    return x + y;
}

可选参数和默认参数

可选参数:使用?进行修饰
默认参数:在声明参数时赋予默认值

(() => {
    class Person {
        name: string
        age: number
        address: string
        constructor(name: string, age: number = 18, address ?: string) {
            this.name = name;
            this.age = age;
            this.address = address;
        }
    }
    const per = new Person("张三", 22, "解放路");
    const per2 = new Person("李四");
    console.log(per);
    console.log(per2);
})()

在这里插入图片描述

剩余参数

剩余参数也叫rest参数,使用…args来表示,放在所有参数的末尾。

(() => {
    function show(str: string, ...args: string[]) {
        console.log(str);
        console.log(args);
    }
    show("a", "b", "c", "d")
})()

在这里插入图片描述

函数重载

函数名相同,函数的参数类型及个数不同
先看一个例子

function add(x: string|number, y: string|number): string|number {
    if (typeof x === 'string' && typeof y === 'string') {
        return x + y;
    } else if (typeof x === 'number' && typeof y === 'number') {
        return x + y;
    }
}
console.log(add(1, '3'))

在这里插入图片描述

这里参数不符合条件,打印出了undefined。
增加函数重载代码。

(() => {
    function add(x: string, y: string): string
    function add(x: number, y: number): number
    function add(x: string|number, y: string|number): string|number {
        if (typeof x === 'string' && typeof y === 'string') {
            return x + y;
        } else if (typeof x === 'number' && typeof y === 'number') {
            return x + y;
        }
    }
    console.log(add(1, '3'))
})()

在这里插入图片描述
ts会有明确的报错提示。

泛型

单个泛型参数

在定义函数、接口、类的时候不能预先确定要使用的数据的类型,而是在使用函数、接口、类的时候才能确定数据的类型。


 function returnArr<T>(value: T): T[] {
     const arr: Array<T> = [value]
     return arr;
 }
 console.log(returnArr("123"))
 console.log(returnArr<string> ("123"))

根据效果,个人认为泛型可以自动做一个类型推断

多个泛型参数。

function fn<T, K>(value1: T, value2: K): [T, K] {
   return [value1, value2]
}
fn<string, number>("1", 2);

泛型接口

在定义接口时,为接口中的属性或方法定义泛型类型
在使用接口时,再指定具体的泛型类型

(() => {
    interface Animal<T> {
        data: Array<T>
        add: (t: T) => void
        get: (id: number) => T
    }
    class Dog {
        id ?: number
        name: string
        constructor(name: string) {
            this.name = name;
        }
    }
    class Dogs implements Animal<Dog> {
        data: Array<Dog> = []
        add(dog: Dog): void {
            dog.id = Date.now() + Math.random();
            this.data.push(dog);
        }
        get(id: number): Dog {
            for (let i = 0, len = this.data.length; i < len; i++) {
                if (this.data[i].id === id) {
                    return this.data[i];
                }
            }
        }
    }
    const dogs = new Dogs();
    dogs.add(new Dog("大黄"));
    dogs.add(new Dog("小黑"));
    console.log(dogs);
})()

在这里插入图片描述

泛型类

定义一个类,类中的属性值是不确定的,方法中的参数及返回值的类型也是不确定的,这种情况使用泛型类。

泛型约束

给泛型指定一些约束规范
如泛型无法识别自身是否有length属性,可以定义一个定义了length属性的接口,并由泛型继承

interface Lengthwise {
	length: number
}
function fn <T extends Lengthwise>(x: T): void {
	console.log(x.length)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值