1.class(類)
1.1類(屬性)
class (類)的屬性和方法,且以大寫字母開頭
class Person {
name: string
gender: string
age: number = 18
constructor(name: string,username:string, gender:string) {
this.name = name
this.username = username
this.gender =gender
}
printAge(age: number) {
this.age = age
console.log(this.age)
}
}
- 創建一個 person類型的新對象,并執行構造函數初始化它
const person = new Person('viole', '王一博', '女')
console.log(person.name, person.username) // viole 王一博
1.1.2 公共,私有與受保護的修飾符
默認為 public
- 公共(public)
在TypeScript里,成員都默認為 public。
class Person {
public name: string
public gender: string
public age: number = 18
}
- 私有(private)
當成員被標記成 private時,它就不能在聲明它的類的外部訪問。比如:
class Friute {
private name: string;
constructor(fName: string) { this.name = fName; }
}
new Friute("Cat").name; // 錯誤: 'name' 是私有的.
- 但是可以在類內部暴露方法,供類對象調用
class Person {
public name: string
protected gender: string
private age: number = 18
constructor(name: string, public username: string, gender: string) {
this.name = name
this.username = username
this.gender = gender // 被保護的,是不能在外面訪問的
}
printAge(age: number) {
this.age = age
console.log(this.age)
}
}
person.printAge(16) // 16
- 受保護的(protected)
protected修飾符與 private修飾符的行為很相似,但有一點不同, protected成員在派生類中仍然可以訪問。例如:
class Person {
public name: string
protected gender: string
private age: number = 18
constructor(name: string, public username: string, gender: string) {
this.name = name
this.username = username
this.gender = gender // 被保護的,是不能在外面訪問的
}
printAge(age: number) {
this.age = age
console.log(this.age)
}
setGender(gender: string) {
this.gender = gender
console.log(this.gender) // 女
}
printName(name: string) {
this.name = name
console.log(this.name)
}
}
const person = new Person('viole', '王一博', '女')
console.log(person.age) // error age is private
console.log(person.gender) // error gender is protected
// 但是可以通過方法賦值
person.setGender('女')
構造函數也可以被標記成 protected。 這意味著這個類不能在包含它的類外被實例化,但是能被繼承。比如:
class Person1 {
protected name: string
protected constructor(theName: string) {
this.name = theName
}
}
class Teacher extends Person1 {
private teacherId: number
constructor(name: string, teacherId: number) {
super(name)
this.teacherId = teacherId
}
public getElevInfo() {
return `my age is ${this.name}and my id is ${this.teacherId}`
}
}
let val = new Teacher('violet', 1234567)
console.log(val.getElevInfo()) // my age is violetand my id is 1234567
let john = new Person1('John') // error: 'Person1' 的構造函數是被保護的.
- readonly(只讀)修飾符
你可以使用 readonly關鍵字將屬性設置為只讀的。 只讀屬性必須在聲明時或構造函數里被初始化。
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 7;
constructor (theName: string) {
this.name = theName;
}
}
let dad = new Octopus("Man with the 7 strong legs");
dad.name = "Man with the 3-piece suit"; // 錯誤! name 是只讀的.
1.2類的繼承
- 創建子類 Student 類繼承于Person
子類可以繼承父類的屬性,但是不能使用私有屬性
class Student extends Person {
studentId: number
constructor(name: string, username: string, studentId: number) {
super(name, username)
this.studentId = studentId
console.log(this.gender) // 被保護的可以訪問 undefined
// console.log(this.age) // error 私有屬性不能在子類中使用
}
studentPrint() {
console.log(this.studentId)
}
// 重寫父類方法
printName(name: string) {
this.name = name
console.log(this.name)
}
}
const minswu = new Student('violet3', '春日宴', 127051)
console.log(minswu)
console.log(minswu.studentPrint()) // 127051
minswu.printAge(16) // 16
console.log(minswu.name, minswu.username, minswu.studentId) // violet3 春日宴 127051
類從基類中繼承了屬性和方法。 這里, minswu是一個 派生類,它派生自 Student 基類,通過 extends關鍵字。 派生類通常被稱作 子類,基類通常被稱作 超類。
1.3 類的get和set
存取器:
TypeScript支持通過getters/setters來截取對對象成員的訪問
- 用于隔離私有屬性和 可公開屬性
class Car {
private _color: string = 'red'
// 私有屬性賦值
set setColor(val: string) {
this._color = val
}
// 私有屬性取值
get getColer() {
return this._color
}
}
let byeCar = new Car()
console.log(byeCar.getColer) // red
byeCar.setColor = 'blue'
console.log(byeCar.getColer) // blue
- 靜態屬性(static)
class Car {
private _color: string = 'red'
// 定義一個靜態常量
// PI: number = 3.14
// 定義一個靜態屬性
static PI: number = 3.14
// 私有屬性賦值
// 定義靜態方法,計算圓
static calcCircle(value: number): number {
return this.PI * value
}
set setColor(val: string) {
this._color = val
}
// 私有屬性取值
get getColer() {
return this._color
}
}
- 通過類實例對象進行訪問PI常量
let byeCar = new Car()
// 定義一個靜態常量
PI: number = 3.14
console.log(byeCar.PI)
console.log(byeCar.calcCircle(8)) // 25.12
- 2.通過static訪問,及通過類直接訪問靜態屬性,靜態方法
console.log(Car.PI) // 3.14
console.log(Car.calcCircle(8)) // 25.12
我們也可以創建類的靜態成員,這些屬性存在于類本身上面而不是類的實例上
2.命名空間(nameSpace)
2.1初識命名空間
“內部模塊”現在稱做“命名空間”。 “外部模塊”現在則簡稱為“模塊”,
優點:解決變量污染,分離文件,便于維護
- 使用namespace關鍵字開辟一個空間
- 里面的屬性,函數需要使用export 關鍵字導出才可以被外部訪問到
namespace MyMath {
export const PI = 3.14
export function sumValue(num1: number, num2: number): number {
return num1 + num2
}
export function calcCircle(val: number) {
return val * PI
}
}
const PI = 3.1415926
// 外面需要使用調用方法,里面需要export
console.log(MyMath.sumValue(5, 10)) // 15
console.log(PI) // 3.1415926
console.log(MyMath.PI) // 3.14
2.2命名空間文件拆分
當應用變得越來越大時,我們需要將代碼分離到不同的文件中以便于維護。
- 將namespace.ts 文件中將sumvalue 和calcCircle 分成獨立的文件
// circle.ts
namespace MyMath {
export const PI = 3.14
export function calcCircle(val: number) {
return val * PI
}
}
//sumvalue.ts
namespace MyMath {
export function sumValue(num1: number, num2: number): number {
return num1 + num2
}
}
- 在namespace.ts中訪問MyMath空間方法
// namespace.ts
console.log(MyMath.sumValue(5, 10)) // error 找不到MyMath
console.log(MyMath.calcCircle(8)) // error 找不到MyMath
方法一:
在index.html中引入拆分出去的sumValue.js,circle.js文件
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script src="./two/app.js"></script>
<script src="./two/circle.js"></script>
<script src="./two/sumValue.js"></script>
<script src="./two/namespace.js"></script>
</html>
- 此時能訪問
// namespace.ts
// 方法一:將 將sumvalue.js 和和calcCircle.js 單獨引入到index.html
console.log(MyMath.sumValue(5, 10)) // 15
console.log(MyMath.calcCircle(8)) // 25.12
方法二:
將三個將sumvalue.circle.ts 以及 namespace.ts合成一個js文件,例如:
- 使用--outfile 關鍵字在終端執行命令,將三個文件合并成app.js
tsc --outfile app.js circle.ts sumvalue.ts namespace.ts
- 在index.html中引用app.js
// app.js
var MyMath;
(function (MyMath) {
MyMath.PI = 3.14;
function calcCircle(val) {
return val * MyMath.PI;
}
MyMath.calcCircle = calcCircle;
})(MyMath || (MyMath = {}));
// 將文件單獨出來
var MyMath;
(function (MyMath) {
function sumValue(num1, num2) {
return num1 + num2;
}
MyMath.sumValue = sumValue;
})(MyMath || (MyMath = {}));
console.log(MyMath.sumValue(5, 10)) // 15
console.log(MyMath.calcCircle(8)) // 25.12
2.3多重命名空間及引入文件
- 第一步,將vscode ts自動轉換成js 插件關閉掉
- 新建circle.ts
// circle.ts
// 給MyMath里面的circle設置了namespace Circle,外部文件能訪問一定要export
namespace MyMath {
export namespace Circle {
export const PI = 3.14
export function calcCircle(val: number) {
return val * PI
}
}
}
- 新建sumValue.ts
namespace MyMath {
export function sumValue(num1: number, num2: number): number {
return num1 + num2
}
}
- 新建app.ts
// app.ts
console.log(MyMath.sumValue(5, 20)) // error
console.log(MyMath.Circle.calcCircle(8)) error 25.12
- 方法一:將代碼合成為app.js(同上)
- 方法二,在app.ts文件里面引入circle.ts文件和sumValue.ts文件
語法: /// <reference path="文見名.ts" />
// app.ts
/// <reference path="circle.ts" />
/// <reference path="sumValue.ts" />
// 第一步,將vscode ts自動轉換成js 插件關閉掉
console.log(MyMath.sumValue(5, 20)) // 25
console.log(MyMath.Circle.calcCircle(8)) // 25.12
- 然后在終端執行命令:
tsc app.ts --outFile app.js
3.模塊module的使用
SystemJS 是一個通用的模塊加載器,它能在瀏覽器或者 NodeJS 上動態加載模塊,并且支持 CommonJS、AMD、全局模塊對象和 ES6 模塊。通過使用插件,它不僅可以加載 JavaScript,還可以加載 CoffeeScript 和 TypeScript。
4.interface(接口)
4.1 接口初識
TypeScript的核心原則之一是對值所具有的結構進行類型檢查。 它有時被稱做“鴨式辨型法”或“結構性子類型化”。 在TypeScript里,接口的作用就是為這些類型命名和為你的代碼或第三方代碼定義契約。
interface Flowers {
name: string
time: number
greet(): void
}
// interface 接口默認都是必填字段
let ginkgo: Flowers = {
name: '牡丹',
time: 3,
greet() {
console.log('洛陽牡丹')
},
}
- 有時,往往會拿type類型與interface比較
type Flowers2 = { name: String; time: number }
interface 可以繼承 type 不能繼承,在類(calss) 中一般使用interface
可選屬性
接口里的屬性不全都是必需的。
// 參數名?: 可選的
interface Flowers {
name: string
time: number
color?: string
greet(): void
}
只讀屬性
- 關鍵字:readonly,只能在初始化賦值不能修改
interface Flowers {
name: string
time: number
color?: string
readonly city: string // 只讀不能修改
greet(): void
}
let ginkgo: Flowers = {
name: '牡丹',
time: 3,
city: '洛陽',
greet() {
console.log('洛陽牡丹')
},
}
// ginkgo.ginkgo = '北京' // error 只讀不能修改
額外的屬性檢查
'[變量:變量類型]':數值類型
interface Flowers {
name: string
time: number
color?: string
readonly city: string // 只讀不能修改
[paramsName: string]: any // 任何類型的任意參數名字
greet(): void
}
// ids 就是任意名字的參數
let ginkgo: Flowers = {
name: '牡丹',
time: 3,
city: '洛陽',
ids: [1.3, 4],
greet() {
console.log('洛陽牡丹')
},
}
function printFlowers(ginkgo) {
console.log(`唯有${ginkgo.name}真國色,花開時節動京城`)
}
printFlowers(ginkgo) //唯有牡丹真國色,花開時節動京城
4.2 接口繼承及類的實現
4.2.1接口在class 中的應用
- 定義一個interface(接口)
// 接口花
interface Flowers {
name: string
time: number
color?: string
readonly city: string // 只讀不能修改
[paramsName: string]: any // 任何類型的任意參數名字
greet(): void
}
- 正常創建類
創建一個類
class Plum {
name: string
age: number
time: number
color: string
}
- implements:通過interface實現一個類
implements:實現 Plum要根據Flowers的屬性或者方法來定義(就是屬性與方法保持一致,必填項類型)
// 根據Flowers 實現梅花類
class Plum implements Flowers {
name: string = '墨梅'
city: string = '門前'
time: number = 3
color: string = 'white'
desc: string = '有大有小 枝上同宿'
greet() {
console.log('洗妝真態,不作鉛華御')
}
- 根據interface 實現一個類
// 定義春天的花接口
interface SpringFlowers {
id: number
moth: number
}
// 根據接口 Flowers,接口SpringFlowers實現類
class Plum implements Flowers, SpringFlowers {
id: number = 101
moth: number = 12
name: string = '墨梅'
city: string = '門前'
time: number = 3
color: string = 'white'
desc: string = '有大有小 枝上同宿'
greet() {
console.log('洗妝真態,不作鉛華御')
}
}
4.2.2 interface 接口的繼承
- 關鍵字extends
// 桃花繼承至花接口
interface Peach extends Flowers {}
const peach: Peach = {
name: '桃花',
city: '門前',
time: 4,
color: 'pink',
greet() {
console.log('人面桃花相映紅')
},
}
console.log(peach, 'peach==')
/* r: "pink", greet: ?}
city: "門前"
color: "pink"
greet: ? ()
name: "桃花"
time: 4 */
5.Generic(泛型)
5.1 在函數中的使用泛型
- 不要泛型的函數可能是這樣
function createSpring(arg: string):string {
return arg
}
console.log(createSpring('小草')) // 小草
- 或者使用any
// 或者在實參不確定類型的情況下,可以使用any
function createSpring(arg: any):any {
return arg
}
但是使用any類型會導致這個函數可以接收任何類型的arg參數,這樣就丟失了一些信息:傳入的類型與返回的類型應該是相同的。如果我們傳入一個數字,我們只知道任何類型的值都有可能被返回。所以,在ts中一般不建議使用any
- 泛型:返回值的類型與傳入參數的類型是相同的,
會根據調用的實參推斷參數類型
符合:類型變量T
function createSpring<T>(arg: T): T {
return arg
}
// 可以在調用的時候,明確指定類型
console.log(createSpring<string>('小草')) //小草
// 交給ts 推斷類型
console.log(createSpring(true)) // true
給createSpring添加類型變量T。 T幫助我們捕獲用戶傳入的類型(比如:number),之后我們就可以使用這個類型。 之后我們再次使用了 T當做返回值類型
- 在接口中使用泛型,定義一個變量 是泛型
interface GenFlowers {
<T>(arg: T): T
}
function createdPlum<T>(arg: T): T {
return arg
}
// 定義一個變量
let plum: GenFlowers = createdPlum
// 交給ts 推斷類型
console.log(plum(30)) //30
// 可以明確指定類型
console.log(plum<string>('墨梅')) //墨梅
- 直接在接口層面上 定義泛型
interface GenSpringFlowers<T> {
(arg: T): T
}
// 在定義調用的時候,需要指定類型,string 或者number
let peachs: GenSpringFlowers<string | number> = createdPlum
console.log(peachs('桃花')) //桃花
- 為泛型添加約束
// 此時我們需要添加約束,參數里面必須要擁有length這個屬性
function getLength<T extends { length: any }>(obj: T): any {
return obj
}
const obj = {
name: 'violet',
age: 30,
length: 10,
}
console.log(getLength(obj)) // {age: 30,name: "violet",length: 10,}
- 或者指定類型 為number,那么傳入的就必須是number,就不能是對象
function getLength<T extends number>(obj: T): any {
return obj
}
const obj = 25
console.log(getLength(obj)) // 25
5.2 泛型Generic類的應用
- 定義一個class
class CountNumber {
num1: number
num2: number
constructor(num1: number, num2: number) {
this.num1 = num1
this.num2 = num2
}
whereabouts(): number {
return this.num1 * this.num2
}
}
const p1 = new CountNumber<number>(10, 40)
console.log(p1.whereabouts()) // 400
- 給class加上泛型
class CountNumber<T> {
num1: T
num2: T
constructor(num1: T, num2: T) {
this.num1 = num1
this.num2 = num2
}
whereabouts(): number {
// 由于是使用的類型T 進行計算時 ts需要在前綴加上+
return +this.num1 * +this.num2
}
}
const p1 = new CountNumber<number>(10, 40)
console.log(p1.whereabouts()) // 400
const p2 = new CountNumber<string>('10', '40')
console.log(p2.whereabouts()) // 400
- 給泛型進行約束,那么就必須傳number
class CountNumber<T extends number> {
num1: T
num2: T
constructor(num1: T, num2: T) {
this.num1 = num1
this.num2 = num2
}
whereabouts(): number {
// 由于是使用的類型T 進行計算時 ts需要在前綴加上+
return +this.num1 * +this.num2
}
}
// 此時傳入的實參就必須是number
// const p1 = new CountNumber('10', '40') // error
const p1 = new CountNumber(10, 40)
console.log(p1.whereabouts()) // 400