为什么没有二级标题?
搭建开发换环境
安装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 |
void | void | 用于标识方法返回值的类型,表示该方法没有返回值。function hello(): void { alert("Hello Runoob"); } |
null | null | 表示对象值缺失。 |
undefined | undefined | 用于初始化变量为一个未定义的值 |
never | never | never 是其它类型(包括 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('猴子')