Typescript笔记

本文最后更新于:2022年9月23日 下午

0.概述

本来报道之前看过一段时间Typescript,暑假又接受了“锻炼”,然后这几天仿佛无所事事(其实有事)。找闫明洋师兄聊天,师兄问了我一个Typescript的面试题,interfacetype两者有什么区别。我才意识到之前看的比较快,细枝末节都略过了,所以这篇笔记记录自己想记的地方,不一定按顺序组织了。

1.基础类型
字符串
  • 注意模版字符串的使用

    1
    2
    3
    4
    5
    6
    7
    let name: string = `Gene`;
    let age: number = 37;
    let sentence: string = `Hello, my name is ${ name }.I'll be ${ age + 1 } years old next month.`;
    //等于
    let sentence: string = "Hello, my name is " + name + ".\n\n" +
    "I'll be " + (age + 1) + " years old next month.";
    //写很长,一直加,不美观
数组
  • 两种方式

    • ```typescript let list: number[] = [1, 2, 3];
      1
      2
      3

      + ```typescript
      let list: Array<number> = [1, 2, 3];
元组
  • “数”组中可以定义不同类型的元素

    1
    2
    3
    4
    let x:[string,number];
    x=['zifuchuan',456];
    //必须按照声明的元组类型进行初始化
    //对元组中数据进行操作的时候,操作的方法必须和操作的元组对象对应
  • 当对元组中新数据进行赋值的时候

    1
    2
    x[3]='World';
    //x[3]可以赋值为(string|number)类型,x[4]=true;报错,x中没有布尔型
枚举
  • 很友好,用起来很舒服

    1
    2
    enum Color {Red, Green, Blue}
    let c: Color = Color.Green;
  • 可以选择手动赋值、加序号

    1
    2
    3
    4
    enum Color {Red = 1, Green, Blue}
    let c: Color = Color.Green;
    enum Color {Red = 2, Green=4, Blue=5}
    let c: Color = Color.Green;
any
  • 已知数组的一部分值,可以用

  • 不清楚值是什么类型的时候可以用

    1
    2
    let list: any[] = [1, true, "free"];
    list[1] = 100;
类型断言
  • 有的时候类型不通过,强制告诉编译器这个类型是我指定的类型

  • 两种方式

    • ```typescript let someValue: any = "this is a string"; let strLength: number = (someValue).length; //<> 尖括号写法
      1
      2
      3
      4
      5

      + ```typescript
      let someValue: any = "this is a string";
      let strLength: number = (someValue as string).length;\
      //as写法
2.有关接口
概念
  • Typescript会对值所具有的结构进行检查

  • 传入的对象参数实际上会包含很多数学

    • 但是编译器只会检查那些必要的属性和定义的类型是否匹配
    • 类检查器不会去检查属性的顺序,只需要相应的属性存在并且类型符合就行
    1
    2
    3
    4
    5
    6
    7
    8
    9
    interface LabelledValue {
    label: string;
    }
    function printLabel(labelledObj: LabelledValue) {
    console.log(labelledObj.label);
    }
    let myObj = {size: 10, label: "Size 10 Object"};
    printLabel(myObj);
    //只要这个label属性存在就行了
可选属性
  • ?解决

    1
    2
    3
    4
    5
    6
    7
    8
    interface SquareConfig{
    color?:string;
    width?:number;
    }
    function createSquare(config:SquareConfig):(color:string,area:number){...}
    // createSquare函数,接收SquareConfig类型的参数,返回参数类型为:{color:string,area:number};
    let mySquare = createSquare({color:'black'}) as SquareConfig;
    // 使用as,将createSquare()函数的返回值类型强制转化为SquareConfig,赋值给mySquare
只读属性
  • readonly解决

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    interface Point{
    readonly x:number;
    readonly y:number;
    }
    let p1:Point ={x:10,y:20};
    p1.x=5; //错误 只能读取,不能修改(重新赋值)

    let a: number[] = [1, 2, 3, 4];
    let ro: ReadonlyArray<number> = a; //ReadonlyArray相当于readonly的二维实现
    ro[0] = 12; // error!
    ro.push(5); // error!
    ro.length = 100; // error!
    a = ro; // error!
  • const的区别

    • const用来声明变量
    • readonly用来声明属性
接口继承
  • implemens关键字继承接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    interface firstClock{
    hours:number;
    }

    interface secondClock{
    minutes:number;
    }

    interface trueClock implements fisrtClock,secondClock{
    seconds:number
    }
    let time = <trueClock>{};
    time.hours=12;
    time.minutes=32;
    time.seconds=17;
  • extends关键字继承类

    • 会继承类的成员但不包括其实现,接口中类的成员只能由这个类的子类实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class Control {
    private state: any;
    }

    interface SelectableControl extends Control {
    select(): void;
    }

    class Button extends Control implements SelectableControl {
    select() { }
    }

    class TextBox extends Control {
    select() { }
    }

    // 错误:“Image”类型缺少“state”属性。
    class Image implements SelectableControl {
    select() { }
    }

    class Location {

    }
3.有关类
  • 就正常定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class People{
    name:string;
    age:number;
    constructor(enterName:string,enterAge:number){
    this.name = enterName;
    this.age = enterAge;
    }
    study():void{
    console.log(`I have been studied for ${this.age} years`);
    }
    }
  • 但是继承的时候要理解一下原理

    • 一个是附加属性的加入,和父类中一样的属性要放在super()里给父类调用
    • super() 表示父类的构造函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    class animal {
    name: string;
    constructor(enterName: string) {
    this.name = enterName;
    }
    func(): void {
    console.log('我的名字叫:' + this.name);
    }
    }

    class dog extends animal {
    age: number; //子类中新添加的属性
    constructor(enterDogName: string, enterAge: number) {
    super(enterDogName); //调用父类的构造函数,
    //调用子类实例的时候(name,age),name属性是父类中有的,用super()去调用父类的构造函数
    this.age = enterAge;
    //新添加的属性,需要用this关键字
    //this关键字必须在super()函数后面
    }
    //重写override 父类中的方法 函数名、参数一样,代码不一样
    func(): void {
    console.log('This is a Dog and I override parent\'s name');
    }
    }

    //同理
    class human extends animal {
    age: number;
    language: string;
    constructor(enterName: string, enterAge: number, enterLanguage: string) {
    super(enterName);
    this.age = enterAge;
    this.language = enterLanguage;
    }
    func(): void {
    console.log('I am human and I can say' + this.language);

    }
    }

    let pe1 = new human('zly', 28, 'CHN');
    //前两个参数都给传到子类human的constructor里,'zly'再传给super()
    pe1.func();
关键词

public

  • 程序里定义的所有成员都可以访问

protected

  • 程序里定义的成员阿崽派生类(子类)中仍然可以访问

private

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

  • 使用getset关键字进行访问(存取器)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    let passcode = "secret passcode";

    class Employee {
    private _fullName: string;

    get fullName(): string {
    return this._fullName;
    }

    set fullName(newName: string) {
    if (passcode && passcode == "secret passcode") {
    this._fullName = newName;
    }
    else {
    console.log("Error: Unauthorized update of employee!");
    }
    }
    }

    let employee = new Employee();
    employee.fullName = "Bob Smith";
    if (employee.fullName) {
    alert(employee.fullName);
    }
抽象类
  • 不能直接被实例化

  • 可以包含实现细节,但具体实现必须在子类中有体现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    abstract class Department {

    constructor(public name: string) {
    }

    printName(): void {
    console.log('Department name: ' + this.name);
    }

    abstract printMeeting(): void; // 必须在派生类中实现
    }

    class AccountingDepartment extends Department {

    constructor() {
    super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
    }

    printMeeting(): void {
    console.log('The Accounting Department meets each Monday at 10am.');
    }

    generateReports(): void {
    console.log('Generating accounting reports...');
    }
    }

    let department: Department; // 允许创建一个对抽象类型的引用
    department = new Department(); // 错误: 不能创建一个抽象类的实例
    department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
    department.printName();
    department.printMeeting();
    department.generateReports(); // 错误: 方法在声明的抽象类中不存在
    let newDepartment = new Department();
    newDepartment.generateReports()//可以的
4. 函数
分类
  • 命名函数

    1
    2
    3
    function add(x,y){
    return x+y;
    }
  • 匿名函数

    1
    2
    3
    let myAdd = function(x,y){
    return x+y;
    }
  • 完整的函数类型

    1
    2
    3
    4
    let myAdd:(x:number,y:number)=>number=
    function(x:number,y:number):number{
    return x+y;
    }
用法
  1. 可选参数

    1
    2
    3
    function myAdd(x:number,y:number,z?:number):number{
    return x+y+z;
    }
  2. 初始默认值

    1
    2
    3
    function buildName(firstName:string,secondName='Ling yi'){
    return firstName+secondName;
    }
  3. 剩余参数

    不知道有多少个变量、想同时操作多个变量的时候使用

    Typescript自动创建参数数组

    1
    2
    3
    4
    function buildName(firstName:string,secondName:string,...restofName:string[]){
    return firstName+secondName+restofName.join("");
    }
    // 编译器创建参数数组,名字是你在省略号( ...)后面给定的名字,你可以在函数体内使用这个数组。
  4. 函数中的this

    独立调用对象中的方法需要注意this关键字的使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    let deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    createCardPicker: function() {
    //返回一个函数
    // return function() {
    // let pickedCard = Math.floor(Math.random() * 52);
    // let pickedSuit = Math.floor(pickedCard / 13);

    // return {suit: this.suits[pickedSuit], card: pickedCard % 13};
    //这里的this是指当前窗口window
    // }
    return ()=> {
    //箭头函数能保存函数创建时的 this值,而不是调用时的值
    let pickCard = Math.floor(Math.random()*52);
    let pickedSuit = Math.floor(pickCard/13);

    return {suit:this.suits[pickedSuit],card:pickCard%13};
    }
    }
    }

    let cardPicker = deck.createCardPicker();
    let pickedCard = cardPicker(); //报错

    alert("card: " + pickedCard.card + " of " + pickedCard.suit);
  5. 方法的重载overload 允许不同参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    let suits = ["hearts", "spades", "clubs", "diamonds"];

    // pickCard方法重载

    function pickCard(x: {suit: string; card: number; }[]): number;
    //提供type {suit: string; card: number; }[] 也就是object

    function pickCard(x: number): {suit: string; card: number; };
    //提供type number 也就是number

    function pickCard(x): any {
    // Check to see if we're working with an object/array
    // if so, they gave us the deck and we'll pick the card

    //因为有了重载函数,可以输入两种预先重载的参数,然后在主函数中进行判断
    //根据参数类型进行相应的操作
    if (typeof x == "object") {
    let pickedCard = Math.floor(Math.random() * x.length);
    return pickedCard;
    }
    // Otherwise just let them pick the card
    else if (typeof x == "number") {
    let pickedSuit = Math.floor(x / 13);
    return { suit: suits[pickedSuit], card: x % 13 };
    }
    }

    let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
    let pickedCard1 = myDeck[pickCard(myDeck)];
    //输入卡片
    console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit);

    let pickedCard2 = pickCard(15);
    //输入数字
    console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function overF(enterNum: number): number;
    function overF(enterStr: string): string;
    function overF(enter): any {
    if (typeof enter == "string") {
    console.log(enter);
    }
    if (typeof enter == 'number') {
    console.log('这是数字' + enter);

    }

    }

    overF('sssss');
    overF(123);
5.泛型
  • 提供一个类型变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    function fn<T>(para: T) {
    return para;
    }
    //可以不指定泛型
    let result1 = fn(10);
    //指定泛型
    let result2 = fn<string>('123');

    function fn2<T, K>(para1: T, para2: K) {
    console.log(para1);
    return para2;
    }
    //可以同时指定两个泛型
    let result3 = fn2<number, string>(123, 'hello');


    interface Inter {
    length: number;
    }

    //泛型继承接口,泛型T必须是Inter的一个实现类
    function fn3<T extends Inter>(a: T) {
    return a.length;
    }

    //泛型实现类
    class MyClass<T>{
    name: T;
    constructor(name: T) {
    this.name = name;
    }
    }

    const mc = new MyClass('hello');

Typescript笔记
https://anonymouslosty.ink/2022/09/21/Typescript笔记/
作者
Ling yi
发布于
2022年9月21日
更新于
2022年9月23日
许可协议