前言
一尾流莺在此预祝大家虎年大吉 ~ !
JavaScript
是弱类型语言, 很多错误只有在运行时才会被发现,而 TypeScript
提供了一套静态检测机制, 可以帮助我们在编译时就发现错误。
随着前端工程化的发展,TypeScript
起到了相当大的作用,可以帮助团队开发避免很多错误的发生。
虽然使用 TypeScript
会让代码量增加,但是会让代码变的更加健壮,更好维护。另外,它的类型推断和语法提示功能属实是可以大幅度提升开发效率的。
比如你写了一个很长的变量,你要么忘了怎么拼的,要么怕写错去复制粘贴,但是有了 TypeScript
你可能只敲了一个字符,整个变量都出来了。
所以说懒才是生产力,这也是我喜欢 TypeScript
的一大原因。
基本类型
可以先 声明变量 再 进行赋值,赋值只可以是 声明时定义的类型,否则会报错
代码语言:javascript复制let a: number;
let b: string;
a = 3;//true
a = '3';//false
b = 'hello';//true
b = 5;//false
可以在 声明变量的同时进行赋值 ,赋值只可以是 声明时定义的类型,否则会报错
代码语言:javascript复制let c: boolean = false;
c = true;//true
c = 'hello';//false
如果变量的声明和赋值是同时进行的,并且没有定义类型, TS
可以根据声明时的类型自动对变量进行类型检测
let d = false;
d = true;//true
d = 123; //false
可以使用 |
来连接多个类型 (联合类型),变量值只可以是联合类型中的一种
let b: 'male' | 'female';
b = 'male';//true
b = 'female';//true
b = 'hello'; //false
let c: boolean | string;
c = true;//true
c = 'aa';//true
c = 3;//false
当 不确定 一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里 共有的属性或方法:
length
不是 string
和 number
的共有属性,所以会报错。
访问 string
和 number
的共有方法 toString()
是没问题的:
function fn(something: string | number): number {
return something.length;//false
return something.toString();//true
}
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:
第二行的 myFavoriteNumber
被推断成了 string
,访问它的 length
属性不会报错。
而第四行的 myFavoriteNumber
被推断成了 number
,访问它的 length
属性时就报错了。
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
console.log(myFavoriteNumber.length); // true
myFavoriteNumber = 7;
console.log(myFavoriteNumber.length); // false
any
表示任意类型,可以任意赋值一个变量,设置类型为 any
后,相当于对该变量关闭了 TS
的类型检测
可以显式或者隐式的设置类型为 any
,只声明,不赋值 ,TS
解析器会自动判断变量类型为 any
在 任意值上 访问 任何属性 都是允许的,也允许调用 任何方法,可以认为,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是 任意值
代码语言:javascript复制//显式any
let d: any;
d = 10;
d = 'aa';
d = false;
//隐式any
let e;
unknown
表示未知类型的值 实际上就是一个类型安全的 any
let f: unknown;
f = 'hello';
any
类型的变量 可以赋值给任意变量 any
会影响其他变量的类型检测
unknown
不可以赋值给其他类型的变量 否则报错
let a:any;
let b:string;
let c:unknown;
b = a;//true 同时关闭了b的类型检测
b = c;//false
可以先进行类型检测,再把 unknown
类型的值赋值给其他类型
let s: string;
if (typeof f === 'string') {
s = f;
}
类型断言 告诉解析器变量的实际类型
两种写法
代码语言:javascript复制//写法一
s = f as string;
//写法二
s = <string>f;
设置函数返回值的类型
代码语言:javascript复制function fn1(): string {
return 'hello';//true
return 3;//false
}
void
用来表示空,以函数为例,表示没有返回值的函数
function fn2(): void {
return;
}
never
表示永远不会返回结果
function fn3(): never {
throw new Error('错误了');
}
object
表示一个 js
对象
let h: object;
h = {};
h = function () {};
但是 js
中万物皆对象,所以检测对象几乎没有什么意义
主要是为了限制对象中的属性,而不是限制是不是一个对象
{}
用来指定对象中包含哪些属性,
属性后面加 ?
表示属性是可选属性 []
表示任意属性
[propName: string]
任意属性名 any
任意类型
let i: { name: string; age?: number; [propName: string]: any };
i = { name: 'hzw' };
i = { name: 'hzw', age: 13 };
i = { name: 'hzw', sad: 'asd' };
定义函数结构
语法:function fn(形参1:类型,形参2:类型,...)=>类型
,参数不符合要求,过多,过少,都会报错
let k: (a: number, b: number) => number;
k = (n1, n2) => {
return n1 n2;
};
string[]
表示字符串数组 Array<string>
number[]
表示数值数组 Array<number>
任意类型 Array<any>
let m: string[];
let n: Array<number>;
let o:Array<any>;
m = ['a', 'b', 'c'];
n = [1,2,3];
o = ['a',1]
数组的一些方法的参数也会根据数组在定义时约定的类型进行限制:push
方法只允许传入 number
类型的参数,但是却传了一个 "8"
类型的参数,所以报错了。
let arr: number[] = [1, 1, 2, 3, 5];
arr.push('8');//false
元组 即固定长度的数组,元素过多或者过少都会报错
但是可以数组方法 push
向元组内添加元素,被称之为"越界元素",但是被添加的元素只能是元组中定义的类型,否则报错
let n: [string, number];
n = ['asd', 1];//true
n = ['asd', 1,'cc'];//false
n.push(1)//true
n.push("vv")//true
n.push(true)//false
enum
枚举类型 适用于在几个值当中选择的情况
enum Gender {
Male,
Famale,
}
let o: { name: string; gender: Gender };
o = {
name: 'hzw',
gender: Gender.Male,
};
console.log(o.gender === Gender.Male); //true
&
表示同时
let p: { name: string } & { age: number };
p = { name: 'hzw', age: 14 };
类型的别名
给类型起一个别名 用 myType
代替 1 | 2 | 3 | 4 | 5
var z: 1 | 2 | 3 | 4 | 5;
let l: 1 | 2 | 3 | 4 | 5;
type myType = 1 | 2 | 3 | 4 | 5;
let q: myType;
q = 1;
编译
编译文件
自动编译单个文件
使用 tsc
命令对 TS
文件进行编辑,编译文件时,使用 -w
指令后,TS
编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。
示例:
代码语言:javascript复制tsc xxx.ts -w
自动编译整个项目
如果直接使用 tsc
指令,则可以自动将当前项目下的所有 ts
文件编译为 js
文件。
但是能直接使用tsc命令的前提时,要先在项目根目录下创建一个ts的配置文件 tsconfig.json
tsconfig.json
是一个 JSON
文件,添加配置文件后,只需 tsc
命令即可完成对整个项目的编译
tsc
tsconfig.json:
文件配置选项
1. include
- 用来指定哪些目录下的ts文件需要被编译
- 默认值:
["**/*"]
**
表示任意目录-
*
表示任意文件
//表示根目录下src目录下任意目录任意文件
"include": [
"./src/**/*"
],
2. exclude
- 用来指定哪些目录下的
ts
文件不需要被编译 - 默认值:
["node_modules", "bower_components", "jspm_packages"]
//表示不编译根目录下src目录下test目录下任意目录任意文件
"exclude":[
"./src/test/**/*"
],
3. extends
- 用来定义 被继承的配置文件
- 引入后,当前配置文件中会自动包含引入文件中的所有配置信息
//当前配置文件中会自动包含根目录下base.json中的所有配置信息
"extends": "./base.json",
4. files
- 用来指定被编译的文件列表,需要把文件一个个列出来比较麻烦,只有需要编译的文件少时才会用到.
//只会编译根目录下01目录下的hello.ts
"files": ["./01/hello.ts"],
compilerOptions
- 编译选项是配置文件中非常重要也比较复杂的配置选项
- 在
compilerOptions
中包含多个子选项,用来完成对编译的配置
1. target
- 用来指定
TS
被编译为的ES
版本 - 可选值:
ES3
(默认)、ES5
、ES6/ES2015
、ES7/ES2016
、ES2017
、ES2018
、ES2019
、ES2020
、ESNext
(最新版本的ES)
//我们所编写的ts代码将会被编译为ES6版本的js代码
"compilerOptions": {
"target": "ES6"
}
2. module
- 用来指定要使用的模块化的解决方案
- 可选值:
CommonJS
、UMD
、AMD
、System
、ES2020
、ESNext
、None
"compilerOptions": {
"module": "CommonJS"
}
3. lib
- 用来指定项目中要使用的库 一般浏览器情况下不需要设置
- 可选值:
ES5
、ES6/ES2015
、ES7/ES2016
、ES2017
、ES2018
、ES2019
、ES2020
、ESNext
、DOM
、WebWorker
、ScriptHost
......
"compilerOptions": {
"lib": ["ES6", "DOM"],
}
4. outDir,rootDir
outDir
用来指定编译后文件所在的目录rootDir
用来指定代码的根目录- 默认情况下,编译后的
js
文件会和ts
文件位于相同的目录,设置outDir
后可以改变编译后文件的位置
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
}
5. outFile
- 将编译后的代码合并为一个文件
- 设置
outFile
后,所有的全局作用域中的代码会合并到同一个文件中 - 如果
module
制定了None
、System
或AMD
则会将模块一起合并到文件之中
"compilerOptions": {
"outFile": "dist/app.js"
}
6.allowJs
- 是否对
js
文件进行编译,默认为false
7.checkJs
- 是否检测
js
代码是否符合语法规范,默认为false
8.removeComments
- 是否移除注释,默认为
false
9.noEmit
- 是否不生成编译后的文件,默认为
false
10.noEmitOnError
- 是否不生成编译后的文件(当出现错误时),默认为
false
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"removeComments": false,
"noEmit": false,
"noEmitOnError": true
}
11.严格检查
- strict
- 启用所有的严格检查,默认值为
true
,设置后相当于开启了所有的严格检查
- 启用所有的严格检查,默认值为
- alwaysStrict
- 总是以严格模式对代码进行编译
- noImplicitAny
- 禁止隐式的
any
类型
- 禁止隐式的
- noImplicitThis
- 禁止类型不明确的
this
- 禁止类型不明确的
- strictBindCallApply
- 严格检查
bind
、call
和apply
的参数列表
- 严格检查
- strictFunctionTypes
- 严格检查函数的类型
- strictNullChecks
- 严格的空值检查
- strictPropertyInitialization
- 严格检查属性是否初始化
12.额外检查
- noFallthroughCasesInSwitch
- 检查
switch
语句包含正确的break
- 检查
- noImplicitReturns
- 检查函数没有隐式的返回值
- noUnusedLocals
- 检查未使用的局部变量
- noUnusedParameters
- 检查未使用的参数
- allowUnreachableCode
- 检查不可达代码
- 可选值:
true
,忽略不可达代码;false
,不可达代码将引起错误
打包
webpack整合
通常情况下,实际开发中我们都需要使用构建工具对代码进行打包;
TS
同样也可以结合构建工具一起使用,下边以 webpack
为例介绍一下如何结合构建工具使用 TS
;
1.初始化项目
进入项目根目录,执行命令 npm init -y
,创建 package.json
文件
2.下载构建工具
代码语言:javascript复制npm i
webpack
webpack-cli
webpack-dev-server
typescript
ts-loader
clean-webpack-plugin
html-webpack-plugin
-D
共安装了7个包:
- webpack:构建工具
webpack
- webpack-cli:
webpack
的命令行工具 - webpack-dev-server:
webpack
的开发服务器 - typescript:
ts
编译器 - ts-loader:
ts
加载器,用于在webpack
中编译ts
文件 - html-webpack-plugin:
webpack
中html
插件,用来自动创建html
文件 - clean-webpack-plugin:
webpack
中的清除插件,每次构建都会先清除目录
3.配置webpack
根目录下创建 webpack
的配置文件 webpack.config.js
// 引入处理路径的模块
const path = require('path');
// 引入自动生成html的插件
const HTMLWebpackPlugin = require('html-webpack-plugin');
// 引入每次打包之前清除dist目录的插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// webpack所有的配置信息都写在modules.exports中
module.exports = {
optimization:{
minimize: false // 关闭代码压缩,可选
},
// 指定入口文件
entry: './src/index.ts',
// 指定打包文件所在的目录
output: {
// 指定打包后文件的目录
path: path.resolve(__dirname, 'dist'),
// 打包后文件的名字
filename: 'bundle.js',
// 禁止使用箭头函数 可选
environment: {
arrowFunction: false,
},
},
// 指定webpack打包时要使用的模块
module: {
// 指定要加载的规则
rules: [
{
// test指定的是规则生效的文件
test: /.ts$/,
// 要使用的loader处理ts文件
use: [
'ts-loader',
],
// 要排除的文件
exclude: /node_modules/,
},
],
},
// 配置webpack插件
plugins: [
//自动生成html
new HTMLWebpackPlugin({
// 自定义title
title: '自定义title',
// 配置模板 打包后的html以该文件为模板
template: './src/index.html',
}),
//自动删除dist目录下的文件
new CleanWebpackPlugin(),
],
// 用来设置哪些文件可以作为模块被引入
resolve: {
extensions: ['.ts', '.js'],
},
};
4.配置TS编译选项
根目录下创建 tsconfig.json
,配置可以根据自己需要
{
"compilerOptions": {
//用来指定TS被编译为的ES版本
"target": "ES2015",
//用来指定要使用的模块化的解决方案
"module": "ES2015",
//所有严格检查的总开关
"strict": true
}
}
5.修改package.json配置
代码语言:javascript复制"scripts": {
//通过webpack进行打包
"build": "webpack",
//通过webpack启动网络服务器,并使用谷歌浏览器打开 支持热更新
"start": "webpack serve --open chrome.exe"
},
6.项目使用
在 src
下创建 ts
文件,并在并命令行执行 npm run build
对代码进行编译;
或者执行 npm start
来启动开发服务器;
Babel
- 除了
webpack
,开发中还经常需要结合babel
来对代码进行转换,以使其可以兼容到更多的浏览器 - 虽然
TS
在编译时也支持代码转换,但是只支持简单的代码转换,对于例如:Promise
等ES6
特性,TS
无法直接转换,这时还要用到babel
来做转换;
1.安装依赖包:
代码语言:javascript复制npm i -D @babel/core @babel/preset-env babel-loader core-js
共安装了4个包,分别是:
- @babel/core:
babel
的核心工具 - @babel/preset-env:
babel
的预定义环境 - @babel-loader:
babel
在webpack
中的加载器 - core-js:
core-js
用来使老版本的浏览器支持新版ES
语法
2.修改webpack.config.js配置文件
代码语言:javascript复制 // 配置babel
{
// 指定加载器
loader: 'babel-loader',
// 设置babel
options: {
// 设置预定义的环境
presets: [
[
// 指定环境插件
'@babel/preset-env',
// 配置信息
{
// 指定浏览器版本
targets: {
chrome: '58',
ie: '11',
},
// 指定corejs版本
corejs: '3',
// 使用corejs的方式 表示usage按需加载
useBuiltIns: 'usage',
},
],
],
},
},
如此一来,使用 ts
编译后的文件将会再次被 babel
处理,使得代码可以在大部分浏览器中直接使用.
接口和泛型
使用 类型声明 来描述一个对象的类型
代码语言:javascript复制type myType = {
name: string;
age: number;
};
const person1: myType = {
name: 'hzw',
age: 18,
};
- 接口用来定义一个类结构,可以当成类型声明去使用
- 接口用来定义一个类中应该包含哪些属性和方法
interface myObiect {
name: string;
age: number;
}
const person2: myObiect = {
name: 'hzw',
age: 18,
};
类型声明和接口的区别:
类型声明不可以重复写 接口可以重复写,内容会自动合并
代码语言:javascript复制 interface myObiect {
name: string;
}
interface myObiect {
age: number;
}
const person2: myObiect = {
name: 'hzw',
age: 18,
};
- 接口主要负责定义一个类的结构,接口可以去限制一个对象的接口:对象只有包含接口中定义的所有属性和方法时才能匹配接口;
- 接口只定义结构 不考虑实际值;
- 接口的作用类似于抽象类,不同点在于:接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法;
interface myClass {
name: string;
bark(): void;
}
定义类时,可以使类去实现一个接口 使用 implements
关键字
class class1 implements myClass {
name: string;
constructor(name: string) {
this.name = name;
}
bark() {
console.log('旺旺旺');
}
}
使用接口定义函数的类型
代码语言:javascript复制interface ISum {
(x: number, y: number): number;
}
let add: ISum = (x: number, y: number): number => {
return x y;
};
定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定)此时泛型便能够发挥作用;
举个例子,下面这段代码 test
函数有一个参数类型不确定,但是能确定的时其返回值的类型和参数的类型是相同的;
由于类型不确定所以参数和返回值均使用了 any
,但是很明显这样做是不合适的:
首先使用 any
会关闭 TS
的类型检查,其次这样设置也不能体现出参数和返回值是相同的类型;
function test(arg: any): any{
return arg;
}
泛型函数
代码语言:javascript复制function test<T>(arg: T): T{
return arg;
}
这里的<T>
就是泛型,那么如何使用上边的函数呢?
方式一(直接使用):
使用时可以直接传递参数使用,类型会由 TS
自动推断出来,但有时编译器无法自动推断时还需要使用下面的方式
test(10)
方式二(指定类型):
也可以在函数后手动指定泛型;
代码语言:javascript复制test<number>(10)
函数中声明多个泛型
可以同时指定多个泛型,泛型间使用逗号隔开
代码语言:javascript复制function test<T, K>(a: T, b: K): K{
return b;
}
test<number, string>(10, "hello");
泛型类
类中同样可以使用泛型:
代码语言:javascript复制class MyClass<T>{
prop: T;
constructor(prop: T){
this.prop = prop;
}
}
泛型继承
也可以对泛型的范围进行约束
使用 T extends MyInter
表示泛型 T
必须是 MyInter
的子类,不一定非要使用接口类和抽象类同样适用;
interface MyInter{
length: number;
}
function test<T extends MyInter>(arg: T): number{
return arg.length;
}
面相对象
定义类
- 使用
class
关键字来定义一个类
class Person {}
- 定义实例属性 需要通过对象的实例去访问
class Person {
name: String = 'hzw';
age: number = 18;
}
const hzw = new Person();
console.log(hzw.name);//hzw
console.log(hzw.age);18
- 使用
static
关键字定义静态属性 通过类访问
class Person {
static age: number = 20;
}
console.log(Person.age);//20
- 使用
readonly
关键字定义只读属性 - 可以同时使用
static
和readonly
关键字定义静态只读属性,static
只能在readonly
前面
class Person {
readonly color: string = 'red';
static readonly height: string = '50px';
}
- 定义实例方法 需要通过对象的实例去访问
class Person {
sayHello(): void {
console.log('hello');
}
}
const hzw = new Person();
hzw.sayHello();//hello
- 使用
static
关键字定义静态方法 通过类访问
class Person {
static sayHello(): void {
console.log('hello,static');
}
}
Person.sayHello();//hello,static
构造函数
- 构造函数 会在对象创建时调用
class Dog {
constructor() {
console.log("构造函数调用了")
}
}
const dog1 = new Dog();//构造函数调用了
- 在构造函数中,可以通过
this
向新建的对象中添加属性
class Dog {
name: String;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
- 在实例方法中,
this
表示当前的实例,在实例方法中可以通过this
来表示当前调用方法的对象
class Dog {
name: String;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
bark(): void {
//在实例方法中可以通过this来表示当前调用方法的对象
console.log(this);
}
}
const dog1 = new Dog('小黑', 3);
dog1.bark();//小黑: Dog {name: "小黑", age: 3}
继承
通过继承可以将多个类中共有的代码写在一个父类中,这样只需要写一次即可让所有的子类都同时拥有父类中的属性
- 定义一个表示动物的类
Animal
class Animal {
name: String;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
bark(): void {
console.log(`动物在叫~~`);
}
}
- 定义一个表示狗的类
Dog
- 使
Dog
类继承Animal
类 - 此时
Animal
被称为父类,Dog
被称为子类 - 使用继承后,子类将会拥有父类所有的属性和方法
class Dog extends Animal {
}
const dog = new Dog('旺财', 3);
console.log(dog);// Dog {name: "旺财", age: 3}
dog.bark();//动物在叫~~
- 定义一个表示猫的类
Cat
- 使
Cat
类继承Animal
类
class Cat extends Animal {
}
const cat = new Cat('小白', 4);
console.log(cat);// Cat {name: "小白", age: 4}
cat.bark();//动物在叫~~
子类可以添加自己独有的属性和方法
代码语言:javascript复制class Dog extends Animal {
run() {
console.log(`${this.name}在跑~~~`);
}
}
const dog = new Dog('旺财', 3);
dog.run();//旺财在跑~~~
重写
如果子类添加了父类相同的方法,子类方法会覆盖父类,被称之为方法重写
代码语言:javascript复制class Dog extends Animal {
bark(): void {
console.log('旺旺旺');
}
}
const dog = new Dog('旺财', 3);
dog.bark();//旺旺旺
super
在类的方法中,super
表示当前类的父类,在子类中可以使用 super
来完成对父类的引用
class Animal {
name: String;
constructor(name: string) {
this.name = name;
}
bark(): void {
console.log(`动物在叫~~`);
}
}
//在类的方法中 super表示当前类的父类
class Dog extends Animal {
bark() {
super.bark();
}
}
const dog = new Dog('旺财');
dog.bark();//动物在叫~~
子类继承父类时,如果子类中也定义了构造方法,必须调用父类的构造方法!
代码语言:javascript复制 //在类的方法中 super表示当前类的父类
class Dog extends Animal {
age: number;
constructor(name: string, age: number) {
//调用父类的构造函数
super(name);
this.age = age;
}
}
属性修饰符
抽象类(abstract class)
- 使用
abstract
开头的类被称为抽象类 - 抽象类和其他类区别不大,只是不能用来创建对象
- 抽象类是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例
- 抽象类中可以添加抽象方法
- 使用
abstract
开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,继承抽象类时抽象方法必须要重写,否则报错
abstract class Animal {
name: String;
constructor(name: string) {
this.name = name;
}
abstract bark(): void;
}
class Dog extends Animal {
bark() {
console.log('旺旺旺');
}
}
属性修饰符
默认情况下,对象的属性是可以任意的修改的,为了确保数据的安全性,在 TS
中可以对属性的权限进行设置
TS
中属性具有三种修饰符:
public
(默认值),可以在类、子类和对象中修改protected
,可以在类、子类中修改private
,可以在类中修改
public
代码语言:javascript复制class Person{
public name: string; // 写或什么都不写都是public
public age: number;
constructor(name: string, age: number){
this.name = name; // 可以在类中修改
this.age = age;
}
sayHello(){
console.log(`大家好,我是${this.name}`);
}
}
class Employee extends Person{
constructor(name: string, age: number){
super(name, age);
this.name = name; //子类中可以修改
}
}
const p = new Person('孙悟空', 18);
p.name = '猪八戒';// 可以通过对象修改
protected
代码语言:javascript复制class Person{
protected name: string;
protected age: number;
constructor(name: string, age: number){
this.name = name; // 可以修改
this.age = age;
}
sayHello(){
console.log(`大家好,我是${this.name}`);
}
}
class Employee extends Person{
constructor(name: string, age: number){
super(name, age);
this.name = name; //子类中可以修改
}
}
const p = new Person('孙悟空', 18);
p.name = '猪八戒';// 不能修改
//Property 'name' is protected and only accessible within class 'Person' and its subclasses.
private
代码语言:javascript复制class Person{
private name: string;
private age: number;
constructor(name: string, age: number){
this.name = name; // 可以修改
this.age = age;
}
sayHello(){
console.log(`大家好,我是${this.name}`);
}
}
class Employee extends Person{
constructor(name: string, age: number){
super(name, age);
this.name = name; //子类中不能修改
//Property 'name' is private and only accessible within class 'Person'.
}
}
const p = new Person('孙悟空', 18);
p.name = '猪八戒';// 不能修改
//Property 'name' is private and only accessible within class 'Person'.
属性存取器
- 对于一些不希望被任意修改的属性,可以将其设置为
private
,直接将其设置为private
将导致无法再通过对象修改其中的属性 - 我们可以在类中定义一组读取、设置属性的方法,这种对属性读取或设置的属性被称为属性的存取器
- 读取属性的方法叫做
setter
方法,设置属性的方法叫做getter
方法
class Person{
private _name: string;
constructor(name: string){
this._name = name;
}
//get 属性名
get name(){
return this._name;
}
//set 属性名
set name(name: string){
this._name = name;
}
}
const p1 = new Person('孙悟空');
// 实际通过调用getter方法读取name属性
console.log(p1.name);
// 实际通过调用setter方法修改name属性
p1.name = '猪八戒';
简写
- 在参数中加修饰符可以达到简写的目的
- 不用声明
name:string
- 构造函数中不用
this.name=name
class Person{
constructor(public name: string){
}
}
//等价于
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
}
后语
到这为止,你就可以使用 ts
进行初步的开发了。但是对于 ts
来说,掌握这些是远远不够的。
再给大家推荐两个学习 ts
的网站。