typescript笔记

43 篇文章 1 订阅
1 篇文章 0 订阅

为什么没有二级标题?

搭建开发换环境

安装nodejs

全局安装 typesctipt

npm i -g typescript

创建一个ts文件:

使用tsc对文件进行编译:

tsc xxx.ts

基本类型

类型声明:

声明一个变量a,同时制定它的类型为number,

a设置为了string,在以后的使用过程中a的值只能是string

const a: string = 'fuck you also !';

// 或者:
const b:string;
b = 'fuckyou';

注意:

  • 在typescript中如果写的有错误代码,但是可以编译为js

  • ts编译可以编译为任意版本的js,默认是编译为较低版本的js

自动推断类型

如果变量的声明和赋值是同时进行的,ts可以自动对变量进行类型检测

let c = false;
// 这里会报错,因为在上面使用时已经制定其为boolean类型
c = 'fuckyou';
指定function传参类型:
function sum(a: number, b: number): number {
    return a + b
}

const res = sum(5, 8);
指定function返回的数值类型:

其中():后面的类型就是指定的方法返回类型

function sum(a: number, b: number): number {
    return a + b
}
基本类型:
数据类型关键字描述
任意类型any声明为 any 的变量可以赋予任意类型的值。
数字类型number双精度 64 位浮点值。它可以用来表示整数和分数。let binaryLiteral: number = 0b1010; // 二进制 let octalLiteral: number = 0o744; // 八进制 let decLiteral: number = 6; // 十进制 let hexLiteral: number = 0xf00d; // 十六进制
字符串类型string一个字符系列,使用单引号(')或双引号(")来表示字符串类型。反引号(****)来定义多行文本和内嵌表达式。let name: string = “Runoob”; let years: number = 5; let words: string = 您好,今年是 ${ name } 发布 ${ years + 1} 周年;`
布尔类型boolean表示逻辑值:true 和 false。let flag: boolean = true;
数组类型声明变量为数组。// 在元素类型后面加上[] let arr: number[] = [1, 2]; // 或者使用数组泛型 let arr: Array<number> = [1, 2];
元组元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。let x: [string, number]; x = ['Runoob', 1]; // 运行正常 x = [1, 'Runoob']; // 报错 console.log(x[0]); // 输出 Runoob
枚举enum枚举类型用于定义数值集合。enum Color {Red, Green, Blue}; let c: Color = Color.Blue; console.log(c); // 输出 2
voidvoid用于标识方法返回值的类型,表示该方法没有返回值。function hello(): void { alert("Hello Runoob"); }
nullnull表示对象值缺失。
undefinedundefined用于初始化变量为一个未定义的值
nevernevernever 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。
字面量的创建:
  • 字面量创建后无法修改,类似于const:
// 使用字面量进行类型声明
let g: 310;

// 使用字面量之后下面无法赋值,会报错
// g = 65;
// g = 5;
  • 字面量可以限制其值:
// 也可以在创建字面量的时候使用|链接多个值:
let h: "fuck you" | "son of bitch" | "shameless";
console.log(`h:${h}`)
  • 限制字面量的类型:
//也可以指定其为多个类型:
let flag: boolean | string;
flag = true;
flag = "fuck the world";
any:

一个变量设置为any后,就会对该变量关闭类型检测,但开发中不建议使用

显式any,在声明时,不指定类型

let b;

隐式any

any不仅影响自己,同时也会影响与它相关的:

let u:any;
u='123465';
let o:string;
//下面这个不会报错,any可以复制给任意变量
o=u;
  • 但是有些情况我们不知道传入的值的类型

可以使用unknown 表示未知类型的值

let y: unknown;
y = 10;
y = 'sad';
let p:'fuck';
//将ubknown赋值给其他类型时,会报错,区别于any
p=y;

//unknown实际上就是一个类型安全的any

避免unknown赋值错误可以:

let y: unknown;
y = 10;
y = 'sad';
let p:'fuck';
// 将ubknown赋值给其他类型时,会报错,区别于any
// p=y;
if(typeof p=='string'){
   p=y; 
}
类型断言
let y: unknown;
y = 10;
let p:'fuck';
// 判断,他可以用来告诉解析器变量的实际类型
p = y as string;
p = <string> y;
void一般作为返回值
// 有返回值:
function fn1(): boolean {
    return false
}

console.log(fn1())

// 表示该函数没有返回值
function fn2(): void {
    console.log('fuck you! fn2')
}

fn2();
never 表示永远不会返回结果:
// never 表示永远不会返回结果:
function fn3(): never {
    throw new Error('报错');
}
fn3();
设置函数结构的类型声明
// 限定一个function的传参和返回值:
// 设置函数结构的类型声明
let d: (a: number, b: number)=>number;
d = function (n1, n2) {
    return n1 + n2;
}
数组(array)
// 表示字符串数组
let e: string[];
e = ['s', 'g', 'sc'];
// number类型数组
let u: Array<number>;
u = [2, 5, 1, 5, 6, 4];
let d3: Array<number>;
d3 = [2, 5, 65, 32, -123];

两种表示方式

元祖(tuple)
//元祖,固定长度的数组,但数组中的值是固定的,使用元祖比较好
let h: [string, string];

h = ['hello', 'world'];
对象(object)

在js中对象什么都可以存储:

// js中的对象
let c2 = {
    name: '八嘎',
    age: 15,
    gender: '男'
};

但在ts中我们可以指定tys中存储的属性类型:

// 指定属性名: propName 指定属性值:any
let c: {
    name: string,
    [propName: string]: any
};

c = {
    name: '椎间孔',
    school: 'fuck you school!'
}
console.log('c:');
console.log(c);

其中[propName: string]: any指定其属性名为任意值

对于不确定是否设置的属性可以使用?表示这个属性是可选的

let c: {
    name: string,
    age?: number,
    [propName: string]: any
};
函数(function)
/*
箭头函数的形式设置函数的类型声明,
语法:(形参:类型,形参:类型...)=>返回值
* */
let s: (a: number, b: number) => number;
//下面传入两个参数是符合定义的
s = function (n1, n2) {
    return n1 + n2;
}
// 如果传入三个参数,报错
/*s = function (n1, n2, n3) {
    return n1 + n2;
}*/
枚举(enum)
// 定义枚举:
enum Gender {
    Male,
    Female
}
let i: { name: String, gender: Gender }
i = {
    name: 'zjk',
    gender: Gender.Female
}

console.log(i.gender == Gender.Male);

// &表示同时:
let j: { name: string } & { age: number };
j = {name: '猴子', age: 15};
类型别名
type myType = string;
type myKey = 1 | 2 | 3 | 4 | 5
let k: myKey;
let m: myType
&表示必须有的多个值
// & 用来连接,表示该值必须有指定的类型参数
let o: { name: string } & { age: number };
o = {
    name: 'fuc',
    age: 23
};

编译选项

  • 自动编译文件:

编译文件时,使用-w指令后ts编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译

示例:

tsc xxx.ts -w

但是这种方式每一个文件都要单独开一个窗口,不适合开发的

设置编译所有ts文件:

在需要编译的目录下新建ts的配置文件:

tsconfig.json

你可以使用的模板:

{
  "compilerOptions": {
    // 采用的模块系统
    "module": "es6",
    // 编译输出目标 ES 版本
    "target": "es6",
    // 删除所有注释,除了以 /!*开头的版权信息。
    "removeComments": true
  }
}

这里你也可以什么都不写:

{
    
}

在什么都不写的情况下运行:

PS D:\myHomeWork\project\WebStudy\typescript\part02> tsc
PS D:\myHomeWork\project\WebStudy\typescript\part02> dir


    目录: D:\myHomeWork\project\WebStudy\typescript\part02


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         2023/3/15     13:47             49 01.js
-a----         2023/3/15     13:41             59 01.ts
-a----         2023/3/15     13:47             64 02.js
-a----         2023/3/15     13:47             68 02.ts
-a----         2023/3/15     13:45            239 tsconfig.json

该目录下的ts文件都被编译了

当然,也可以使用tsc -w监视该文件夹下所有的ts文件

include

include 用来指定哪些ts文件需要被编译:

/*
ts编译器的配置文件,
ts编译器可以根据它的信息来对代码进行编译
  include 用来指定哪些ts文件需要被编译
    其中 ** 表示任意目录, * 表示任意文件

*/
{
  "include": [
    "./src/**/*"
  ]
}
exclude

exclude 用来排除

  • 默认值:[“node_modules” , “bower_components” , “jspm_packages”]
{
  "include": [
    "./src/**/*"
  ],
  "exclude": [
    "./src/hello/**/*"
  ]
}
extends
  • 定义被继承的配置文件
  • 示例:
"extends":"./config/base"
  • 上述示例中,当配置文件中会自动包含config目录下config目录下base.json中的所有配置信息
compilerOptions
  • 编译器的选项,是配置文件中非常重要也比较复杂的配置选项
  • 在 compilerOptions 中包含多个子选项,用来完成对编译的配置

项目选项

target

用来指定ts被编译的es版本,默认情况下ts会被转为es3版本的js

{  
  "include": [  
    "./src/**/*"  
  ],
	"compilerOptions": {  
	  "target": "es6"  
	}
}

如果值为ESNext表示编译为最新版本的es

注意:如果不知道有哪几个版本,可以乱填一个,编译报错会告诉你可以填哪些版本

lib
  • 用来指定项目中要使用的库
  • 一般情况下不动它
module
  • 模块
    指定要使用的模块化规范
{  
  "include": [  
    "./src/**/*"  
  ],  
  "compilerOptions": {  
    "target": "es6",  
    "module": "es2015",  
	}  
}
outDir
  • 用来指定编译后文件所在的目录
{  
  "include": [  
    "./src/**/*"  
  ],  
  "compilerOptions": {  
    "target": "es6",  
    "module": "es2015",  
    "lib": [],  
    "outDir": "./dist"  
  }  
}
outFile

将编译后的ts文件打包为一个文件
设置outFile之后,所有的全局作用域中的代码会合并到同一个文件中
如果你想要合并自己的js文件,那么需要将modules改为system:

"module": "system",
allowJs

是否编译指定目录下的js文件:

"allowJs": false

如果为false,那么编译时不会编译js文件,只会编译ts文件

checkJs

检查js代码是否符合规范
默认为false

"checkJs": false,
removeComments

是否移除注释
默认值为false

"removeComments": false
noEmit

不生成编译后的文件

"noEmit": false
noEmitOnError

有错误时不生成编译文件
默认值为false

"noEmitOnError": false
alwaysStrict

设置编译后的js是否使用严格模式
并且在浏览器中执行的性能要好一些
默认为false

"alwaysStrict": false

设置为true:
在编译后的js文件头部加上:

"use strict";

注意:
对于有export,import这些导出导入模块的js文件,它是不会加上"use strict";,因为它已经自动使用了严格模式

noImplicitAny

设置没有指定参数类型时,是否允许推断其为any类型
开发中我们要避免显式的any,
对于下面的代码就是使用的是显式any,需要避免:

function fn(a, b) {  
    return a + b  
}

默认是为true

"noImplicitAny": false

如果 为false,那么像是下面的代码就会报错:

function fn(a, b) {  
    return a + b  
}

此时如果加上类型就不会报错了:

function fn(a: number, b: number) {  
    return a + b  
}
noImplicitThis

是否允许不明确类型的this

"noImplicitThis": true

默认为true

此时为false,那么下面就会报错:

function fn2() {
    // 下面这个this是不明确的
    alert(this);
}

当你指定后就不再报错:

function fn2(this: Window) {
    // 下面这个this是不明确的
    alert(this);
}
strictNullChecks

严格的检查空值

默认值为false

如果改为true:

"strictNullChecks": true

对于下面的ts代码:

let box1 = document.getElementById("box1");
box1.addEventListener("click", function () {
    console.log('click')
})

这里的box1可能为空,那么在编译的时候就会报错

可以这样解决:

let box1 = document.getElementById("box1");
if (box1 != null) {
    box1.addEventListener("click", function () {
        console.log('click')
    })
}

或者使用?:

let box1 = document.getElementById("box1");
box1?.addEventListener("click", function () {
    console.log('click')
})
strict

所有严格检查的总开关,如果这个为true,那么下面几个都可以不写,一般开发建议写true所有严格检查的总开关,如果这个为true,那么下面几个都可以不写,一般开发建议写true

"strict": true,

可以省略下面这几个:

noEmitOnError,
alwaysStrict,
noImplicitAny,
noImplicitThis,
strictNullChecks

通过webpack对ts编译
最基础的配置:

目录结构:

PS D:\myHomeWork\project\WebStudy\typescript\part03> dir

    目录: D:\myHomeWork\project\WebStudy\typescript\part03

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         2023/3/16     11:33                dist
d-----         2023/3/16     11:36                node_modules
d-----         2023/3/16     11:34                src
-a----         2023/3/16     11:37            472 package.json
-a----         2023/3/16     11:25            103 tsconfig.json
-a----         2023/3/16     11:35            557 webpack.config.js

package.json:

{
  "name": "part03",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "start": "webpack server --open"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "html-webpack-plugin": "^5.5.0",
    "ts-loader": "^9.4.2",
    "typescript": "^4.9.5",
    "webpack": "^5.76.2",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.12.0"
  }
}

tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2015",
    "module": "ES2015",
    "strict": true
  }
}

webpack.config.js:

const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: "./src/index.ts", output: {
        path: path.resolve(__dirname, 'dist'), filename: 'bundle.js',
    }, module: {
        rules: [{
            test: /\.ts$/, use: 'ts-loader', exclude: /node_modules/
        }]
    },
    // 插件:
    plugins: [new htmlWebpackPlugin({
        // 自定义生成文件的title
        // title: 'index title'
        // 自定义模板
        template: './src/index.html'
    })]
}

这里主要是使用webpack.config.js中的配置文件

兼容目标浏览器版本:

package.json:

{
  "name": "part03",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "start": "webpack server --open"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/core": "^7.21.3",
    "@babel/preset-env": "^7.20.2",
    "babel-loader": "^9.1.2",
    "clean-webpack-plugin": "^4.0.0",
    "core-js": "^3.29.1",
    "html-webpack-plugin": "^5.5.0",
    "ts-loader": "^9.4.2",
    "typescript": "^4.9.5",
    "webpack": "^5.76.2",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.12.0"
  }
}

tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2015",
    "module": "ES2015",
    "strict": true
  }
}

webpack.config.js:

const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
    entry: "./src/index.ts", output: {
        path: path.resolve(__dirname, 'dist'), filename: 'bundle.js',
    }, module: {
        rules: [{
            test: /\.ts$/,
            // 这里的使用顺序是从后往前
            use: [
                {
                    loader: 'babel-loader',
                    options: {
                        presets: [
                            [
                                "@babel/preset-env",
                                // 配置信息:
                                {
                                    // 要兼容的目标版本
                                    targets: {
                                        "chrome": "88"
                                    },
                                    "core-js": "3",
                                    // 使用模式,这里设置的是按需加载
                                    "useBuiltIns": "usage"
                                }
                            ]
                        ]
                    }
                },
                'ts-loader'],
            exclude: /node_modules/
        }]
    },
    // 插件:
    plugins: [
        new htmlWebpackPlugin({
            // 自定义生成文件的title
            // title: 'index title'
            // 自定义模板
            template: './src/index.html'
        }),
        new CleanWebpackPlugin()
    ]
}

面向对象

面向对象简介

对象中主要包含两个部分:

  • 属性
  • 方法
定义类:
class 类名{
    静态属性/实例属性

    方法(){
        
    }    
}
  • 示例:
class Person {
    private name: string;
    private age: number;
    // 定义实例属性(通过定义实例才能看到的属性为实例属性)
    grade: string = '大三';
    // 当然也可以不写类型
    gre = '孙悟空';
    // 使用static定义静态属性,静态属性要通过类来访问
    static word: string = 'fuck you!';
    // 定义只读属性,它无法修改
    readonly only: string = 'fuck you only read';
    // 定义一个静态的只读属性
    static readonly onlyStatic: string = 'fuck you only onlyStatic';

    constructor(name: string, age: number, grade?: string) {
        this.name = name;
        this.age = age;
    }

    sayName() {
        console.log('我是' + this.name);
    }

    sayAge() {
        console.log('我的年龄是' + this.age);
    }
}

console.log("Person.word:")
console.log(Person.word)

const p1 = new Person('张三', 15, "高二")
console.log(p1)
console.log("p1.only:")
console.log(p1.only)
console.log('Person.onlyStatic,静态只读属性:')
console.log(Person.onlyStatic)

console.log('p1的name:')
p1.sayName()
console.log('p1的age:')
p1.sayAge()
定义一个方法
  • 实例方法

可以直接在类中使用:

class Person {
    private name: string;
    private age: number;
    constructor(name: string, age: number, grade?: string) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log('我是' + this.name);
    }
    sayAge() {
        console.log('我的年龄是' + this.age);
    }
}
  • 静态方法:
class Person {
    private name: string;
    private age: number;
    constructor(name: string, age: number, grade?: string) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log('我是' + this.name);
    }
    sayAge() {
        console.log('我的年龄是' + this.age);
    }
    static func(){
        console.log('这是一个类调用的function')
    }
}

要注意静态方法只有类可以调用,实例无法调用

构造函数
class Constructor {
    name: string | undefined = '普通的狗';
    age: number | undefined = 5;

    // 在实例方法中,this就是表示当前的实例
    // 在构造函数中当前对象就是当前新建的那个对象
    // 可以通过this向新建的对象中添加属性
    constructor(name?: string, age?: number) {
        this.name = name;
        this.age = age;
    }
}
继承

例如在下面的代码中

// 继承
(function () {
    class Dog {
        name: string | undefined;
        age: number | undefined;

        constructor(name?: string, age?: number) {
            this.name = name;
            this.age = age;
        }

        sayHello() {
            console.log('hello,汪汪汪')
        }
    }

    class Cat {
        name: string | undefined;
        age: number | undefined;

        constructor(name?: string, age?: number) {
            this.name = name;
            this.age = age;
        }

        sayHello() {
            console.log('hello,喵喵喵')
        }
    }

    const dog = new Dog("旺财1", 23);
    dog.sayHello();
    const cat = new Cat("肥仔", 20)
    cat.sayHello();
})();

他们的name,age属性一模一样的,如果我们想要去创建其他动物,并且有name和age,那么就为了避免这些重复

#### super
  • 在方法中super表示当前的父类
(function () {
    class Animal {
        name: string;
        constructor(name: string) {
            this.name = name;
        }
        sayHello() {
            console.log('动物在叫')
        }
    }
    class Dog extends Animal {
        sayHello() {
            // 在方法中super表示当前的父类
            super.sayHello();
        }
    }
    const dog = new Dog("张三");
    dog.sayHello();
})();
  • 如果在子类中重写了父类的构造函数,那么在子类构造函数中必须对父类的构造函数重写
(function () {
    class Animal {
        name: string;
        constructor(name: string) {
            this.name = name;
        }
        sayHello() {
            console.log('动物在叫')
        }
    }
    class Dog extends Animal {
        age: number;
        sayHello() {
            // 在方法中super表示当前的父类
            super.sayHello();
        }
        // 如果在子类中重写了父类的构造函数,那么在子类构造函数中必须对父类的构造函数重写
        // 子类的构造函数中传递的属性必须把父类中需要传递的属性也写上
        constructor(name: string, age: number) {
            // 调用父类的构造函数
            super(name);
            this.age = age;
        }
    }
    const dog = new Dog("张三", 23);
    dog.sayHello();
})();

如果这里子类的constructor中没有super父类的传递属性,会报错

抽象类

一些父类是用作被继承的,而且我们不希望它被实例化,那么此时就可以使用abstract来修饰这个类:

// 抽象类
(function () {
    // 使用 abstract 表示该类为一个抽象类,无法被实例化,只能被继承
    abstract class Animal {
        name: string;

        constructor(name: string) {
            this.name = name;
        }

        sayHello() {
            console.log('动物在叫')
        }
    }

    class Dog extends Animal {
        sayHello() {
            // 在方法中super表示当前的父类
            super.sayHello();
        }
    }

    const dog = new Dog("张三");
    dog.sayHello();
// 此时animal也可以创建对象,但是我们不希望用animal来创建对象
})();

使用 abstract 表示该类为一个抽象类,无法被实例化,只能被继承

重现类中可以写抽象方法

抽象方法
  • 抽象方法使用 abstract 修饰

  • 抽象方法只能写在抽象类中,子类必须对抽象方法进行重写

例如:

// 抽象类
(function () {
    // 使用 abstract 表示该类为一个抽象类,无法被实例化,只能被继承
    abstract class Animal {
        name: string;
        constructor(name: string) {
            this.name = name;
        }
        // 抽象方法使用 abstract 修饰
        // 抽象方法只能写在抽象类中,子类必须对抽象方法进行重写
        abstract sayHello(): void;
    }
    class Dog extends Animal {
        sayHello() {
            // 在方法中super表示当前的父类
            console.log('狗在叫')
        }
    }
    const dog = new Dog("张三");
    dog.sayHello();
// 此时animal也可以创建对象,但是我们不希望用animal来创建对象
})();
接口
定义对象结构
  • 接口用来定义一个类结构的,用来定义一个;类中应该包含哪些属性和方法
    • 时接口也可以当成类型声明来使用
    • 接口是可以重复声明的
    • 如果有两个同名接口,生效是两个同时生效
// 接口
(function () {
    type myType = {
        name: string,
        age: number
    };
    /*
    接口用来定义一个类结构的,用来定义一个;类中应该包含哪些属性和方法
        同时接口也可以当成类型声明来使用
        接口是可以重复声明的
        如果有两个同名接口,生效是两个同时生效
    * */
    interface myInterface {
        name: string;
        age: number;
    }
    interface myInterface {
        gender: string;
        sayHell(): void;
    }
    const obj: myType = {
        name: 'zs',
        age: 12
    };
    const obj2: myInterface = {
        name: 'zs',
        age: 12,
        gender: '男',
        sayHell() {
            console.log('对象中的sayHello')
        }
    };
})();
定义类结构
  • 接口在定义类的时候可以去限制类的结构

    • 接口中所有的属性都不能有实际的值
    • 接口只定义对象的结构,而不考虑实际值
    • 在接口中的方法都是抽象方法
  • 定义类时,可以使类去实现一个接口

  • 实现接口就是使类满足接口的需求

// 接口
(function () {
    interface myInterface {
        name: string;
        age: number;
    }
    interface myInterface {
        gender: string;
        sayHell(): void;
    }
    /*
    接口在定义类的时候可以去限制类的结构
        接口中所有的属性都不能有实际的值
        接口只定义对象的结构,而不考虑实际值
        在接口中的方法都是抽象方法
    * */
    /*
    定义类时,可以使类去实现一个接口
        实现接口就是使类满足接口的需求
    * */
    class inst implements myInterface {
        name: string;
        age: number;
        gender: string;
        constructor(name: string, age: number, gender: string) {
            this.name = name;
            this.age = age;
            this.gender = gender;
        }
        sayHell(): void {
            console.log('inst sayHello')
        }
    }
})();
属性的封装
公有,私有属性

像是下面这个类,它定义的属性都可以在类的外面被访问到:

class Person {
        name: string;
        age: number;

        constructor(name: string, age: number) {
            this.name = name;
            this.age = age;
        }
    }
const per = new Person('猴子', 18);
    // 现在属性是在对象中设置的,属性可以任意的被修改
    // 属性可以被任意修改,导致我们对象中的数据非常不安全
per.name = '猪'
console.log(per)

在这种情况下对某些属性的修改可能会不安全,因此可以将不想修改的属性设置为私有属性:

class Animal {
        // public修饰的属性可以在任意位置访问(修改) 默认值
        // private私有属性,私有属性只能在类内部进行访问(修改)
        /*
        我们可以在类中添加方法使其私有属性在类的外面可以被访问
        * */
        private _name: string;
        private _age: number;
        private gender: number;

        constructor(name: string, age: number, gender: number) {
            this._name = name;
            this._age = age;
            this.gender = gender;
        }
    }
  • 属性默认为public,public可以在任意位置被访问,包括子类
修改和获取私有属性

属性就是用来获取和使用的,因此,设置和获取私有属性时,可以通过在类中为其设置方法:

class Animal {
        // public修饰的属性可以在任意位置访问(修改) 默认值
        // private私有属性,私有属性只能在类内部进行访问(修改)
        /*
        我们可以在类中添加方法使其私有属性在类的外面可以被访问
        * */
        private _name: string;
        private _age: number;
        private gender: number;

        constructor(name: string, age: number, gender: number) {
            this._name = name;
            this._age = age;
            this.gender = gender;
        }

        // 像下面一样,可以使用这些方法来设置和访问到其私有属性
        getName(): string {
            return this._name;
        }

        setName(value: string) {
            this._name = value;
        }

        getAge(): number {
            return this._age;
        }

        setAge(value: number) {
            this._age = value;
        }
    }
    const a1 = new Animal('狗', 10, 20);
    // 虽然下面这个可以编译为js,但在ts中会报错,如果不想在有错误的情况下也通过编译,可以在 tsconfig 中配置有错不会编译为js
    // a1.gender = '猫'
    a1.setName('傻猫');
    console.log(a1)
  • get和set方法被称为属性的存取器

存取器有另一种写法:

    class Animal {
        private _name: string;
        private _age: number;
        private _gender: number;
        
        constructor(name: string, age: number, gender: number) {
            this._name = name;
            this._age = age;
            this._gender = gender;
        }
        // ts中设置get方法可以:
        get name(): string {
            return this._name;
        }

        set name(value: string) {
            this._name = value;
        }

        get age(): number {
            return this._age;
        }

        set age(value: number) {
            this._age = value;
        }

        get gender(): number {
            return this._gender;
        }

        set gender(value: number) {
            this._gender = value;
        }
    }

    const a1 = new Animal('狗', 10, 20);
    // 虽然下面这个可以编译为js,但在ts中会报错,如果不想在有错误的情况下也通过编译,可以在 tsconfig 中配置有错不会编译为js
    // a1.gender = '猫'
    // a1.setName('傻猫');
    console.log(a1.name)
    a1.name = '猪'
    console.log(a1)
  • 这种方法不会改变我们已有的习惯

get:

 console.log(a1.name)

set:

a1.name = '猪'
protected

protected 受保护的类,这个属性只能在当前类和其子类中被访问

protected word: string;
属性定义在构造函数中

直接把属性写在构造器中:

class Fruit {
        constructor(public name: string, public age: number) {
            this.name = name;
            this.age = age;
        }
}
泛型
  • 在一个变量不明确类型的时候整一个泛型来表示这个变量的类型
泛型的定义

下面是一个普通的函数:

function fn1(a: number): number {
    return a
}

但是如果此时你并不确定该输入哪种的变量类型,那么此时就可以使用泛型:

function fn2<T>(a: T): T {
    return a
}

在使用时:

function fn2<T>(a: T): T {
    return a
}

// 或者不指定泛型,ts可以自动对类型进行判断
fn2(20)
// 指定泛型
fn2<string>('hello')

当然也可以为多个形参指定泛型:

function fn3<T, R>(a: T, b: R): T {
    console.log(b)
    return a
}

// 最好手动将泛型指定,降低出错的几率
fn3('fn', 369)
使用接口对泛型做出限制:
// 如果想通过接口对泛型做出限制:
interface Inter {
    length: number;
}

// T extends Inter 表示泛型T必须实现Inter实现类(子类)
function fn4<T extends Inter>(a: T) {
    return a.length;
}

当然,类也可以使用接口来对其做出数据类型做出限制:

interface Inter {
    length: number;
}

class MyClass<T> {
    name: T;
    constructor(name: T) {
        this.name = name;
    }
}

const mc = new MyClass('猴子')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无名之辈无名之辈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值