一、ts介紹
是javascript的超集,遵循最新的ES5 ES6規范。ts擴展了js的語法。
二、安裝與編譯
Npm install -g typescript cnpm install -g typescript yarn global add typescript
查看安裝成功與否 新打開終端 輸入:tsc -v
運行: tsc helloword.ts
vscode編譯:因為瀏覽器不認識ts代碼需要我們編譯, 在終端輸入tsc + 文件名.后綴
會在同級生成一個以js結尾的文件
為了節省開發時間,每次寫好ts代碼后能夠自動編譯
1.創建
ts.config.json
的文件tsc --init
生成配置文件 修改配置文件中outDir
可配置編譯后的Js存放位置
2.vscode點擊:任務->運行任務-> tsc:監視-tsconfig.json(老版本vscode)
終端-> 運行任務-> typescript -> 監視tsconfig.json 即可
三、數據類型
ts中為了使編碼更規范,更有利于維護,增加了類型校驗:
布爾類型(bollean)
數字類型(number)
字符串類型(string)
數組類型(array)
元組類型(tuple)
枚舉類型(enum)
任意類型(any)
null和undefined
void類型
never類型
1.布爾類型
eg. var flag:boolean=true
如果寫falg = “str”
,編譯不通過會報錯
2.數字類型(整數、浮點數都ok)
Var a:number = 123
3.字符串類型
4.數組類型 OK 有兩種方式
方式一:let arr:nuber[] = [1, 2, 3, 4]
方式二:let arr:Array<number>=[11, 23, 353, 34]
5.元組類型(屬于數組的一種,可以指定數組中每一項的多種類型)
Let arr:[string, number, boolean] = [“ts”, 1, true]
6.**枚舉類型 ** (用于標識狀態和固定值)
隨著計算機的不斷普及,程序不僅只用于數值計算,還更廣泛用于處理非數值的 數據。例如:性別、月份、顏色、單位、學歷等,都不是數值數據。
事先考慮到某一變量可能去的值,盡量用自然語言中含義清楚的單詞來表示他的每一個值,這種方法稱為枚舉方法
enum 枚舉名{
標識符[=整型常數],
標識符[=整型常數],
...
標識符[=整型常數]
}
Enum flag {
Success=1,
Error=-1
}
Let f:flag = flag.success / flag.error就代表一個值
若枚舉中沒有賦值的話,會輸出占位的索引
如果是:
Enum color {red, blue=5, orange}
Let c:color=color.red 輸出c為其索引 0
Let c:color = color.blue 輸出c為其值 5
Let c:color = color.orange 輸出c為 6 自動跟隨前一個進行累加
7.任意類型 any
Let num:any=123
Num=”str”
用于獲取節點之后操作dom可以使用any類型
8.**null
undefined
**(其他never類型的子類型)
如果定義了變量未賦值,輸出個該變量為undefined 但是會報錯
所以要聲明變量的時候,在變量后加undefined
如果是該變量可能是number 也可能是undefined 就 let num:number | undefined
null也是如此
一個元素是多種類型,any類型可以囊括這些內容,還有一個其他形式:
Let num:number | null | undefiend
9.void類型 :表示沒有任何類型,一般用于定義方法的時候方法沒有返回值
Function run():void {
Console.log(‘run’)
}
run();
10.never
類型 是其他類型,(null undefined的子類型)代表不會出現的值。意味著聲明never的變量只能被never類型所賦值
Let a:undefined;
a = undefined
Let b:null;
b = null;
Let a :never;
a=132; //錯誤寫法
a =(() => {
Throw new Error(‘錯誤”)
})() //正確寫法
四、函數
函數也是需要指明類型的
//函數聲明類
function run():string {
return 'run'
}
fun2();
//匿名函數
var fun2=function():number {
return 123
}
fun2();
ts中定義方法傳參
//函數聲明
function getInfo(name: string, age:number):string {
return `${name} --- ${number}`
}
console.log(getInfo('zhangsan', 20));
//匿名函數
let getInfo2 = function(name: string, age:number):string {
return `${name} --- ${number}`
}
console.log(getInfo('zhangsan', 20));
沒有返回值得函數
function run():void {
console.log('run')
}
run();
方法的可選參數
es5方法的實參和形參可以不一樣,但是ts不可以,此時需要配置可選參數
即在可能不會傳遞的參數后面添加 ?
function getInfo(name: string, age?:number):string {
if (age) {
return `${name} --- ${number}`
} else {
return `${name} --- 就不告訴你 `
}
}
//alert(getInfo('張三', 123)) 都可輸出
//alert(getInfo('張三')) 都可輸出
注意:可選參數必須配置到參數的最后面
默認參數
es5里面沒法設置默認參數,es6和ts都可以設置默認參數
function getInfo(name: string, age:number=12):string {
if (age) {
return `${name} --- ${number}`
} else {
return `${name} --- 就不告訴你 `
}
}
//alert(getInfo('張三')) 都可輸出,且age是默認的
//alert(getInfo('張三', 123)) 都可輸出
剩余參數
function sum(a: number, b:number, c:number, d:number):number {
return a + b+c+d
}
sum(1, 2, 3, 4)
//三點運算符(剩余參數) 接受形參傳來的值
function sum(...result:number[]):number {
let sum = 0;
for(var i = 0; i < result.length; i ++) {
sum += result[i];
}
return sum
}
sum(1, 2, 3, 4, 5, 6)
//剩余參數三點運算另一種形式
function sum(a:number, ...result:number[]):number {
let sum = a;
for(var i = 0; i < result.length; i ++) {
sum += result[i];
}
return sum
}
sum(1, 2, 3, 4, 5, 6)
函數重載
java中方法的重載,重載的是兩個或兩個以上同名函數,但他們的參數不一樣,這時會出現函數重載的情況
ts中的重載,通過為同一個函數提供多個函數類型定義來試下多種功能的目的
ts為了見佛那個es5和es6 重載的寫法 和java有區別
//es5中 出現同名方法,后面的會替換上面的方法
function css(config:any):any {
...
}
function css(config:any, value:any):any {
...
}
//ts中的重載
function getInfo(name: string):string;
function getInfo(age: number):number;
function getInfo(str: any):any {
if(typeof str === 'string') {
return '我是,’+ str;
} else {
return ‘我的年齡是,’ + str
}
}
alert(getInfo('張三')) //正確
alert(getInfo(12)) //正確
alert(getInfo(true)) //錯誤
//----------------------------------------------
//參數一樣
function getInfo(name: string):string;
function getInfo(name: string, age: number):string;
function getInfo(name: string, age?:any):any {
if (age) {
return '我叫,' + name + '我的年齡是' + age;
} else {
return '我叫, ' + name
}
}
alert (getInfo('張三')) //正確
alert (getInfo(123)) //錯誤
alert (getInfo('張三', true)) //錯誤
箭頭函數
this指向的問題, 箭頭函數的this指向上下文
//es5
setTimeout(function() {
alert('run')
}, 1000)
//箭頭函數
setTimeout(() => {
alert('run')
}, 1000)
五、ts中的類
- 通過
class
類來定義
class Person {
name:string; //屬性 前面省略了public關鍵詞
constructor(n:string) { //構造函數 實例化類的時候觸發的方法
this.name = n;
}
run():void {
alert(this.name);
}
}
let p = new Person('張三');
p.run();
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
getName():string {
return this.name;
}
setName():void {
this.name = name;
}
}
let p = new Person('張三')
alert(p.getName());
p.setName('李四')
alert(p.getName());
- ts中實現繼承 extends / super
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
run():void {
return `${this.name}在運動`
}
}
//繼承
class Web extends Person {
constructir(name: string) {
super(name); /*初始化父類的構造函數*/
}
let w = new Web('李四');
alert(w.run());
ts中繼承 父類的方法和子類的方法一致
如果父類和子類都有同樣的方法 調用子類的就會執行子類方法,先去找子類再找父類類里的修飾符
提供了三種修飾符
-
public
: 表示共有。 在當前類里面、子類、類外部都可以訪問 -
protected
: 表示保護類型。 在當前類里面、子類里面可以訪問, 類外部無法訪問 //控制臺會報錯,但是會輸出, -
private
: 表示私有。 在當前類里面可以訪問,子類和類外部都無法訪問
屬性如果不加修飾符 默認為共有public
class Person {
public name: string; //公有屬性
constructor(name: string) {
this.name = name;
}
run():string {
return `${this.name}在運動`
}
}
class Web extends Person {
constructir(name: string) {
super(name); /*初始化父類的構造函數*/
}
let w = new Web('李四');
alert(w.run());
- 靜態屬性 靜態方法
class Person {
public name: string
public age: number=12
//靜態屬性才能在靜態方法中調用
static sex = "男"
constructor(name:string) {
this.name = name
}
run() {
alert(`${this.name}在運動`) //實例方法
}
work() {
alert(`${this.name}在工作`) //實例方法
}
//靜態方法 沒法直接調用類里的屬性
static print() {
alert('方法' + this.age) //會報錯
}
static print() {
alert('方法' + Person.sex) //調用成功
}
}
let p = new Pweson('張三');
p.run();
p.work();
//調用靜態方法
Person.print();
//使用靜態屬性
alert(Person.sex)
-
多態:父類定義一個方法不實現,讓繼承他的子類去實現 每一個子類有不同的表現
//多態也是一種繼承的表現,屬于繼承
class Animal {
name:string;
constructor(name: string) {
this.name = name
}
eat() {
console.log('吃的方法')
}
}
class Dog extends Animal {
construactor(name: string) {
super(name)
}
eat() {
return this.name + '吃狗糧'
}
}
class Cat extends Anmal {
construactor(name: string) {
super(name)
}
eat() {
return this.name + '吃貓糧'
}
}
-
抽象類:它是提供其他類繼承的基類,不能直接被實例化
用abstract
關鍵字定義抽象類和抽象方法,抽象類中的抽象方法不包含其具體實現并且必須在派生類中實現 abstract抽象方法只能放在抽象類里面 抽象類和抽象方法用來定義標準
//抽象類和抽象方法用來定義標準 標準:Animal這個類要求他的子類必須包含eat方法
abstract class Animal {
abstract eat():any;
}
let a = new Animal() //錯誤的寫法 不能直接被實例化
正確寫法
//抽象類和抽象方法用來定義標準 標準:Animal這個類要求他的子類必須包含eat方法
abstract class Animal {
public name:string;
constructor(name:string) {
this.name = name;
}
abstract eat():any; //該方法必須實現
run() {
console.log('其他方法可以不實現')
}
}
let a = new Animal() //錯誤的寫法
class Dog extends Animal {
constructor(name:any) {
super (name);
}
//抽象類的子類必須實現抽象類里面的抽象方法
eat() {
console.log(this.name + '吃糧食')
}
}
let d = new Dog('小花花');
d.eat();
六、ts中的接口
接口的作用:在面向對象的編程中,接口是一種規范的定義,它定義了行為和動作的規范,在程序設計里面,接口起到一種限制和規范作用,接口起到一種限制和規范的作用,接口定義了某一批類所需要遵守的規范,接口不關心這些類的內部狀態數據,也不關心這些類里方法的實現細節,它之規定這批類里必須提供某些方法,提供這些方法的類就可以滿足實際需要。ts中的接口類似于java,同時還增加了更靈活的接口類型,包括屬性、函數、可索引和類等。 相當于定義標準。
通過
interface
進行定義
- 屬性類接口
- 對傳入對象參數進行約束
//就是傳入對象的約束 是屬性接口
interface FullName {
firstNmae: string; //注意 以分號結束
secondName: string;
}
function printName(name:FullName) {
//必須傳入對象 firstName secondName
console.log(name.firstName + '--' + name.secondName)
}
printName('123') //錯誤的寫法
printName({firstName: '張', secondName: '三'}) //正確
printName({ age: 20, firstName: '張', secondName: '三'}) //錯誤寫法 因為多了age,內容必須只有firstName和secondName
let obj = {
age: 20, //但是當調用的時候就會報錯
firstName: '張',
secondName: '三'
}
printName(obj); //正確寫法 且推薦此使用 外層定義只要有firstName和secondName就行
- 對批量方法進行約束
interface FullName {
firstNmae: string; //注意 以分號結束
secondName: string;
}
function printName(name:FullName) {
//必須傳入對象 firstName secondName
console.log(name.firstName + '--' + name.secondName)
}
function printInfo(name:FullName) {
//必須傳入對象 firstName secondName
console.log(name.firstName + name.secondName )
}
let obj = {
age: 20,
firstName: '張',
secondName: '三'
}
printName(obj);
printInfo({firstName: '李', secondName: '四'})
- 可選屬性
interface FullName {
firstName: string;
secondName?: string; //可傳可不傳
}
function getName(name: FullName) {
console.log(name)
}
getName({firstName: 'xixixi', secondName: '啦啦'})
getName({firstName: 'xixixi'}) //也可編譯成功
- 函數類型接口: 對方法傳入的參數 以及返回值進行約束 可以做批量約束
//實現加密的函數類型接口
interface encrypt {
(key: string, value: string): string; //參數是key和value 返回值是string類型
}
let md5:encrypt = function(key: string, value: string):string {
//模擬操作
return key + value
}
md5('name', 'zhangsan')
- 可索引接口,數組、對象的約束(不常用)
//定義數組的方式
let arr:number[] = [123, 34555]
let arr1:Array<string>=['23g', 'err4']
//可索引接口 對數組的約束 1
interface UserArr {
[index: number]:string
}
let arr:UserArr=['aaaa', 'bbbb'];
console.log(arr[0])
//對對象的約束
interface UserObj{
[index:string]:string
}
let arr:UserObj = {name: '20'}
-
類類型接口:對類的約束 和 抽象類相似
implements
不是繼承,是實現接口
interface Animal {
name: string;
eat(str: string):void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
eat() {
console.log(this.name + '吃狗糧')
}
}
let d = new Dog('小黑')
d.eat();
class Cat implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
eat(food:string) {
console.log(this.name + food)
}
}
let c = new Cat('小花')
d.eat('老鼠')
- 接口擴展,接口可以繼承接口
interface Animal {
eat(): void;
}
interface Person extends Animal { //person繼承animal
work();
}
class Web implements Person {
public name:string;
constructor(name: string) {
this.name = name
}
eat() {
console.log(this.name + '喜歡吃饅頭')
}
work() {
console.log(this.name + '喜歡工作')
}
}
let w = new Web('小李')
w.eat()
interface Animal {
eat(): void;
}
interface Person extends Animal { //person繼承animal
work();
}
class Programmer {
public name:string;
constructor(name: string) {
this.name = name
}
coding(code:string) {
console.log(this.name + code)
}
}
class Web extends Programmer implements Person { //既繼承又實現接口
constructor(name: string) {
super(name)
}
eat() {
console.log(this.name + '喜歡吃饅頭')
}
work() {
console.log(this.name + '喜歡工作')
}
}
let w = new Web('小李')
w.eat()
w.coding('寫ts代碼')
七、ts中的泛型
-
泛型的定義
泛型:軟件工程中,我們不僅要創建一致的定義好的API,同時也要考慮重用性。 組件不僅能夠支持當前的數據類型,同時也能支持未來的數據類型,這在創建大型系統時為你提供了十分靈活的功能。
在像C#和java這樣的語言中,可以使用泛型來創建可重用的組件,一個組件可以支持多種類型的數據。這樣用戶就可以以自己的數據類型來使用組件。
通俗理解:泛型就是解決 類、接口、方法的復用性、以及對不特定數據類型的支持
- 泛型函數
//例如同時返回兩個不同類型的函數 容易代碼冗余
function getData1(value: string):string {
return value;
}
function getData2(value: number): number {
return value
}
//可以使用any類型來進行同時輸出,但是使用any放棄了類型檢查,傳入什么,返回什么
//泛型就出現了
泛型可以支持不特定的數據類型 要求,傳入的參數和返回的參數一致。
T
或者是任意大寫字母。(建議使用T
)表示泛型,具體什么類型是調用這個方法的時候決定的
function getData<T>(value: T):T {
return value;
}
getData<number>(123);
function getData<T>(value: T): any {
return 'sfdsfgfdgdfg'
}
getData<number>(123); //參數必須是number
getData<string>('dfdsfdsfg');
- 泛型類
//泛型類: 比如有個最小堆算法,需要同時支持返回數字和字符串兩種類型 通過類的泛型來實現
class MinClass {
piblic list:number[] = [];
add(num: number) {
this.list.push(num)
}
min() {
let minNum = this.list[0];
}
}
- 泛型接口
//函數類型接口
interface ConfigFn{
(value1: string, value2: string): string;
}
let setData:ConfigFn = function(value1: string, value2: string):string {
retirn value1+value2;
}
setData('name': '張三')
//第一種泛型接口
interface ConfigFn{
<T>(value: T): T;
}
let getData: ConfigFn = function<T>(value: T):T {
return value;
}
getData<string>('張三') //正確
getData<string>(1234) //錯誤
//第二種泛型接口
interface ConfigFn<T>{
(value: T): T;
}
function getData<T>(value: T):T {
return value;
}
let myGetData:ConfigFn<string>=getData;
myGetData('20'); //正確
myGetData(20); //錯誤
-
泛型類--延伸
1.定義個User類 作用:隱射數據庫字段
2.定義個MysqlDb的類 用于操作數據庫
3.然后把User類作為參數傳入到MysqlDb中
//把類作為參數來約束數據傳入的類型
class User {
username: string | undefined;
password: string | undefined;
}
class MysqlDb {
add(user: User): boolean {
// console.log(user);
return true;
}
}
let u = new User();
u.username = '張三';
u.password = '123456';
let Db = new MysqlDb();
Db.add(u);
//把類作為參數來約束數據傳入的類型
class ArticleCate {
title: string | undefined;
desc: string | undefined;
status: number | undefined;
}
class MysqlDb {
add(info: ArticleCate): boolean {
// console.log(info);
return true;
}
updated(info: T, id: number): boolean {
console.log(info)
console.log(id)
return true
}
}
let a= new ArticleCate();
a.title = "國內";
a.desc = "國內新聞";
a.status = 1
let Db = new MysqlDb();
Db.add(a);
發現以上兩種寫法在每操作一次數據庫表的時候 都需要重新指定值得類型,所以使用泛型動態的定義類型,避免代碼重復封裝
//操作數據庫的泛型類
class MysqlDb<T> {
add(info: T): boolean {
// console.log(info);
return true;
}
}
//給User表增加數據
//1.定義一個user類 和數據庫進行映射
class User {
username: string | undefined;
password: string | undefined;
}
let u = new User();
u.username = '張三';
u.password = '123456';
let Db = new MysqlDb<User>(); //可以對傳入的數據進行校驗
Db.add(u);
//賦值方式2 使用構造函數將值提前賦進去
class User {
username: string | undefined;
password: string | undefined;
constructor(params: {
username: string | undefined,
password: string | undefined,
//或者是可選參數 記得加?
}) {
this.username = params.username;
this.password = params.password;
}
}
let u = new User({
username: '張三',
password: '123456'
});
let Db = new MysqlDb<User>(); //可以將類作為參數傳入到泛型類中進行數據的約束及驗證
Db.add(u);
-
ts類型、接口、類、泛型綜合使用--ts封裝統一操作Mysql Mongodb Mssql的底層庫
定義一個操作數據庫的庫 支持Mysql Mongodb Mssql
要求1 Mysql Mongodb Mssql功能一樣 都有add update delete get方法
注意:約束統一的規范,以及代碼重用
解決方案:需要約束規范所以要定義接口,需要代碼重用所以用到泛型
1.接口:在面向對象的編程中,接口是一種規范性的定義,它定義了行為和動作的規范
2.泛型 通俗理解:泛型就是解決 類 接口 方法的復用性
interface DBI<T> {
add(info: T): boolean;
update(info: T, id: number): boolean;
delete(id: number): boolean;
get(id: number): any[];
}
//定義一個操作mysqul數據庫的類 注意:要實現泛型接口 這個類也應該是一個泛型類
class MysqlDb<T> implements DBI<T> {
constructor() {
console.log('數據庫建立連接')
}
add(info: T): boolean {
console.log(info)
return true
}
update(info: T, id: number): boolean {
throw new Error('Method not implemented')
}
delete(id: number): boolean {
throw new Error('Method not implemented')
}
get(id: number): any[] {
let list = [
{
title: ‘xxx’,
desc: 'xxxxx'
},
{
title: ‘xxx’,
desc: 'xxxxx'
},
]
return list;
}
}
//定義一個操作mssqul數據庫類型的類
class MsSqlDb<T> implements DBI<T> {
constructor() {
console.log('數據庫建立連接')
}
add(info: T): boolean {
throw new Error('Method not implemented')
}
update(info: T, id: number): boolean {
throw new Error('Method not implemented')
}
delete(id: number): boolean {
throw new Error('Method not implemented')
}
get(id: number): any[] {
throw new Error('Method not implemented')
}
}
//操作用戶表 定義一個類和數據表做映射
class User {
username: string | undefined;
password: string | undefined;
}
let u = new User();
u.username = '戰三';
u.password = "123456";
let oMysql = new MysqlDb<User>();
oMysql.add(u)
八、ts中的模塊
模塊的概念(官方)
關于屬于的一點說明:ts1.5里的術語名已經發生了變化。 “內部模塊”現在稱作“命名空間”。“外部模塊”現在簡稱為“模塊” 模塊在其自身的作用域里執行,而不是在全局作用域里。
這意味著定義在一個模塊里的變量,函數,類等等在模塊外部是不可見的,除非你明確的使用export形式一導出他們。相反,如果想使用其他模塊導出的變量,函數、類、接口等的時候,你必須要導入他們,可以使用import形式之一
模塊的概念(自己的理解)
我們可以把一些公共的功能單獨抽離成一個文件作為一個模塊。
模塊里面的變量 函數 類等默認是私有的,如果我們要在外部訪問模塊里面的數據(變量、函數、類)
我們需要通過export暴露莫苦熬里面的數據(變量、函數、類)。
暴露后通過import引入模塊就可以使用模塊里面暴露的數據(變量、函數、類)
引用名字過長的時候 可以使用 xx as aa來,此后調用使用aa代替xx即可
import { getData as get } from './......'
你是前端嘛?是的話,我就不用寫了 和js沒差的 不是的話 那你就先成為一個前端再看吧
九、ts的命名空間
在代碼量較大的情況下,為了避免各種變量命名沖突,可將相似功能的函數、類、接口等放置到命名空間,可以將代碼包裹起來,只對外暴露需要外部訪問的對象,命名空間內的對象通過export暴露
命名空間和模塊的區別
命名空間:內部模塊,主要用于組織代碼,避免命名沖突
模塊:ts的外部模塊簡稱,例如代碼的復用,一個模塊里可能有多個命名空間
namespace A {...........} //定義了一堆內容
namespace B {...........} //定義了一堆內容 兩者中的內容可以有重復的
如果想要外部暴露,可以在需要暴露的內容前面加export
,使用可以通過命名空間打點使用內部內容即可
把命名空間定義成模塊并且暴露使用