整理之前學習ts時的一些筆記。
安裝
npm install -g typescript // 報無權限
sudo npm install -g typescript
tsc -v // tsc,ts編譯器,查看版本
// hello.ts
const hello = (name:string)=>{ return `hello ${name}` }
hello('yuki')
tsc hello.ts //編譯 ===> 生成 hello.js
tsc -w hello.ts //監(jiān)聽hello.ts 的變化
node hello.js //運行 js 文件
或者安裝 ts-node ,將以上兩步合并為一步 ts-node hello.ts
編譯后,函數(shù)會出現(xiàn)(2393)函數(shù)實現(xiàn)重復,猜測可能是vscode的bug(不確定)
在項目根目錄添加配置文件 tsconfig.json即可(空文件也可)
基礎類型
let isDone: boolean = false;
let age: number = 18;
let firstName: string = "yuki";
let message: string = `Hello,${firstName},age is ${age}`;
let u: undefined = undefined;
let n: null = null;
let num: number = undefined;
any 和 聯(lián)合類型
let notSure: any = 4;
notSure = "a string";
notSure = true;
notSure.getName();
let numberOrString: number | string;
numberOrString = "hhh";
numberOrString = 1;
數(shù)組Array 和 元祖Tuple
// 數(shù)組 Array
let arrOfNumbers: number[]=[1,2,3]
arrOfNumbers.push(5)
// 元祖 Tuple
let user:[string,number]=['1',3]
interface 接口
對 對象的形狀(shape)進行描述
對 類(class)進行抽象
interface Person {
readonly id:number, // readonly 用于對象屬性,不允許修改該值
name: string;
age?: number; // ? 表示 非必須
}
let yuki: Person = {
id:1111,
name: "yuki",
age: 20, // 此處允許不加age
};
yuki.id = 2222 // error , id readonly,不允許修改
函數(shù) 和 類型推斷
如下,
z 為可選參數(shù)。需要注意,必選參數(shù) 必須放在 可選參數(shù) 之前,否則報錯
或者用es6的寫法, z:number = 0 ,不傳的話默認為0
// function add ():number{} 此處的number 規(guī)定了輸出的類型為number
function add(x:number,y:number,z?:number):number{
if(typeof z ==='number'){
return x+y+z
}
return x+y
}
let result1 = add(1,2,3)
let result2 = add(1,2)
注意,下圖中,不是es6中的箭頭函數(shù)。而是tsc(ts編譯器)的 類型推斷

let str= 'str'
str= 123 // error , 因為ts推斷出 str 是string類型
Class 類
默認是public,允許外部和子類訪問
private 不允許外部和子類訪問
protected 不允許外部訪問,允許子類訪問
readonly 可訪問,不可修改
class Animal {
private name:string
constructor(name:string){
this.name=name
}
}
const snake = new Animal('lili')
console.log(snake.name) // error,外部不允許訪問
snake.name='lucy' // error,外部不允許訪問
class Dog extends Animal {
break() {
return `${this.name} is barking`; // error 子類同樣無法訪問
}
}
子類繼承父類,復雜場景時可能無法滿足需求,故,可用接口interface提供公共部分
類可以同時繼承多個接口,implements (類繼承接口就必須實現(xiàn)這個接口里面寫的方法)
接口可以繼承接口,extends
interface Radio {
switchRadio():void // void 什么都不返回
}
interface Battery{
checkBatteryStatus()
}
// 方法一:CellPhone 同時implements Radio,Battery
class Car implements Radio {
switchRadio(){ }
}
class CellPhone implements Radio,Battery{
switchRadio(){ }
checkBatteryStatus(){ }
}
// 方法二:RadioWithBattery 繼承 Radio, CellPhone implements RadioWithBattery
interface RadioWithBattery extends Radio{
checkBatteryStatus(){ } // 繼承了Radio的switchRadio(){ } ,并添加checkBatteryStatus(){ }
}
class CellPhone implements RadioWithBattery{
switchRadio(){ }
checkBatteryStatus(){ }
}
Enum 枚舉
默認從0開始賦值,每個值自動遞增
也可以自行賦值,number 或 string 等均可
enum Direction {
Up, // 若 賦值 Up=10,則Down為11, Direction[10]為Up
Down,
Left,
Right
}
console.log(Direction.Up) // 0
console.log(Direction[0]) // 'Up' 雙向
編譯后,可發(fā)現(xiàn)轉為js后,是一個自執(zhí)行函數(shù)
// js
var Direction;
(function (Direction) {
Direction[Direction["Up"] = 0] = "Up";
Direction[Direction["Down"] = 1] = "Down";
Direction[Direction["Left"] = 2] = "Left";
Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
常量枚舉(加const)
const enum Direction {
Up = 'up',
Down = 'down'
}
const value = 'up'
console.log(value === Direction.Up) // true
編譯后:
// js
var value = "up";
console.log(value === "up" /* Up */);
常量枚舉成員在使用的地方會被內(nèi)聯(lián)進來,
之所以可以這么做是因為,常量枚舉不允許包含計算成員;
如上,編譯時,并沒有 Direction 變量的,因此常量枚舉會對性能有一定提升。
泛型 (一)
如下,自定義一個泛型T,函數(shù)入?yún)㈩愋蚑,出參同樣T(使入?yún)⒊鰠⒈3忠粯拥念愋停?br> 當入?yún)閟tring,出參同樣是string;入?yún)閚umber,出參同樣number
function echo<T>(arg: T): T {
return arg;
}
const res = echo("str");
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
const res2 = swap(["str", 123]);
泛型(二):約束泛型
interface IwithLength { length: number; } // 入?yún)⒈仨毎?length屬性
function echoWithLength<T extends IwithLength>(arg: T): T {
console.log(arg.length);
return arg;
}
const arr = echoWithLength([1, 2]);
const obj = echoWithLength({ x: 1, length: 1 });
const str = echoWithLength('hhh')
泛型(三):類和接口
class Queue<T> {
private data = [];
push(item: T) {
return this.data.push(item);
}
pop(): T {
return this.data.shift();
}
}
const queue = new Queue<number>();
queue.push(1);
console.log(queue.pop().toFixed());
const queue2 =new Queue<string>()
queue2.push('str')
console.log(queue2.pop())
interface Iplus<T> {
(a: T, b: T): T; // 函數(shù),入?yún)⒁缓腿雲(yún)⒍門,出參為T
}
function plus(a: number, b: number): number {
return a + b;
}
function connect(a: string, b: string): string {
return a + b;
}
const num: Iplus<number> = plus;
const str: Iplus<string> = connect;
當我新建另一個ts文件:
let isDone: boolean = false
//報錯,提示 'isDone' was also declared here.
在默認狀態(tài)下,typescript 將 DOM typings 作為全局的運行環(huán)境,
當我聲明 isDone 時, 與 DOM 中的全局 window 對象下的isDone屬性出現(xiàn)了重名。
解決方法:在腳本文件最后一行,添加 export {}; 將文件聲明為模塊
(在 Typescript 中,只要文件存在 import 或 export 關鍵字,都被視為 module)
類型別名
使用關鍵字type,多用于聯(lián)合
type PlusType = (x: number, y: number) => number;
function sum(x: number, y: number): number {
return x + y;
}
const sum2: PlusType = sum; // 代替 const sum2: (x: number, y: number) => number = sum
類型斷言
通過類型斷言這種方式告訴編譯器類型,只在編譯階段起作用
let someVal: any = 'str'
let strLength: number = (<string>someVal).length // 尖括號
let strLength2: number = (someVal as string).length // JSX 只可使用as語法斷言
聲明文件
https://www.runoob.com/typescript/ts-ambient.html
目的:為了借用 TypeScript 的各種特性來使用第三方庫文件
(declare 定義的類型只會用于編譯時的檢查,編譯結果中會被刪除。)
如,
declare var jQuery:(selector:string)=>any
把這些聲明單獨放在一個文件,稱為聲明文件,以 .d.ts 為后綴,如 jQuery.d.ts
一般而言,所有ts文件都可獲得這些類型定義,若無法獲取,可在根路徑的tsconfig.json中配置tsc編譯器
{ "include":["**/*"] }
DefinitelyTyped (http://definitelytyped.org/)
該組織提供了各類聲明文件,安裝即可,無需自己創(chuàng)建聲明文件
npm install --save-dev @types/jquery