TypeScript 是 JavaScript 的類型的超集,它能夠編譯成純 JavaScript。編譯出來的 JavaScript 能夠運行在任何瀏覽器上。TypeScript 編譯工具能夠運行在任何服務器和任何系統上。TypeScript 是開源的。html
如下內容均出自於 TS入門教程node
以及 Ts 官網的一些內容,沒有基礎的小夥伴直接看打了⭐️的內容便可。jquery
看了以後怎麼搭個環境寫一寫?git
mkdir demo
cd demo
touch 1.ts
複製代碼
打開vscode,打開控制檯,切換到問題 tabes6
歐了,開始嘗試 ts 吧github
let isDone: boolean = false;
// 使用構造函數 Boolean 創造的對象不是布爾值
複製代碼
是全部類型的子類型npm
void類型不能賦值給 number編程
let u: undefined = undefined;
let n: null = null;
let num: number = undefined;
let u: undefined;
let num: number = u;
複製代碼
通常表示函數沒有返回值。用在變量上沒有什麼卵用。json
function warnUser(): void {
console.log("This is my warning message");
}
let a: void = undefined
let a: void = 'undefined' // 報錯,這是字符串
複製代碼
跟它類似的類型還有
undefined
和null
在不開啓嚴格空檢查的狀況下--strictNullChecks
,他們能夠賦值給全部已經定義過***其餘類型***的變量。 也就是說他們是全部類型的子類型數組
let a: undefined = undefined
let a: null = null
複製代碼
TypeScript裏的全部數字都是浮點數。 這些浮點數的類型是 number。支持十進制和十六進制字面量二進制和八進制字面量。
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
// ES6 中的二進制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的八進制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
複製代碼
單雙引
''
""
,模板字符的都被視爲字符串
let str:string = ''
複製代碼
有多種聲明數組的方式
類型 + []
來表示數組:const arr: number[] = [1,2,3]
const arr2: string[] = ['1','2']
複製代碼
const arr2: Array<number> = [1,2,3,3]
const arr2: Array<string> = [1,2,3,3]
複製代碼
interface NumArr {
[index: number]: number;
}
let numArr: NumArr = [1,2,3];
複製代碼
let list:any[] = [1,"z",{}]
複製代碼
// 表示一個肯定數組長度和類型的寫法
const arr:[string,number] = ['2',3]
複製代碼
就是僞數組的定義
官方已給了各自的定義接口 Arguments
, NodeList
, HTMLCollection
function sum() {
let args: IArguments = arguments;
}
複製代碼
js中沒有這類型,仿照強類型語言來的。值只能爲數字,不定義默認值得狀況爲從0開始。
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
// c = 1
enum Number {one = 10, two}
let c: Number = Number.two;
// c = 11
複製代碼
指代全部的類型
let a: any = '123'
let a = 123; // 不聲明默認 any
複製代碼
表示永遠不存在的值,通常會用來寫拋出異常或推斷爲返回值爲never的函數。(好比return一個其餘的never類型)
function error(message: string): never {
throw new Error(message);
}
error('a')
複製代碼
非簡單類型 也就是除number,string,boolean,symbol,null或undefined以外的類型。
function create(o: object | null): void{
console.log(o);
};
create({ prop: 0 }); // OK
create(null); // OK
create([]); // OK
create('a'); // error
複製代碼
在 TypeScript 中,咱們使用接口(Interfaces)來定義對象的類型。
對對象的描述
接口通常首字母大寫。
賦值的時候,變量必須和接口保持一致。
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
複製代碼
不想徹底匹配某個接口,經過
?
表示這個屬性是可選的仍然不容許添加未定義的屬性
interface Person {
name: string;
age?: number;
}
let tom: Person = {
name: 'Tom'
};
複製代碼
讓接口容許添加任意的屬性值
[propName: string]: any;
interface Person {
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
複製代碼
一旦定義了任意屬性, 那麼肯定屬性和
?
可選屬性都必須是任意屬性的子集
interface Person {
name: string;
age?: number;
[propName: string]: string;
}
let p:Person = {
name: 'zzc',
age: 12, // error , 定義了 propName 必須將值設定爲 string 類型
gender: 'male' ,
}
複製代碼
至關因而常量了,初次賦值後不能從新賦值 作爲變量使用的話用
const
,若作爲屬性則使用readonly
。
interface demo {
readonly a: string; // readonly定之後不能改值
b: number
}
let obj: demo = {
a: 'ss',
b: 1
}
obj.a = 'aa' // error
obj.b = 2 // success
複製代碼
只讀的約束存在於第一次給對象賦值的時候,而不是第一次給只讀屬性賦值的時候
interface Person {
readonly id: number;
}
const tom: Person = {} // error
tom.id = 1 // error,
複製代碼
會報兩次錯,第一個是由於指定了 id,但沒有給 id 賦值
第二個錯是給只讀屬性id賦值了
經過
ReadonlyArray
定義的數組,再也沒法改變了。
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = [1,2,3];
a[0] = 10 // success
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // 注意! 將readonly的值賦值給一個可變得數組也是不行的。
a = ro as Array<any> // 可是能夠用斷言重寫
複製代碼
常見的函數聲明方式有: 函數聲明 & 函數表達式
用 ts 定義函數要考慮它的輸入和輸出
function sum(a:number,b:number):number{
return a+b
}
// 形參和實參數量要一致
sum(1) // error
sum(1,2) //3
sum(1,2,3) // error
複製代碼
// 方式 1
let sum = function(a:number,b:number):number {
return a + b;
}
// 方式二
let sum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
複製代碼
方式一中只對等號右側的匿名函數定義了類型,左邊是ts經過類型推論定義出來的
方式二纔是給 sum 定義類型,**其中的 =>
不是 es6的 =>
** ,它用來表示函數的定義,左邊是輸入類型,須要用括號括起來,右邊是輸出類型。
由於和 es6箭頭函數可能形成混淆,最好用方式一;
經過?
給函數定義可選參數
可選參數後面不容許再出現必須參數了
若是給參數添加了默認值,ts 會自動識別爲可選,且不受上一條規則的限制。
function sum(a:number,b?:number){}
function sum(a?:number,b:number){} // error
function sum(a:number = 1,b:number){} // 默認值,識別爲可選,且不報錯
複製代碼
使用…rest獲取剩餘參數,使用數組類型去定義它
剩餘參數必須是函數的最後一個參數
function (a, ...items:any[]){}
function (...items:any[], a){} // error
複製代碼
重載容許一個函數接受不一樣數量或類型的參數時,做出不一樣的處理。
能夠重複定義一個函數的類型
function say(somthing:string):string; function say(somthing:number):string; // 以上是函數定義 // 如下是函數實現 function say(somthing:string|number):string|number {
return somthing
}
複製代碼
注意,TypeScript 會優先從最前面的函數定義開始匹配,因此多個函數定義若是有包含關係,須要優先把精確的定義寫在前面。
類型斷言(Type Assertion)能夠用來手動指定一個值的類型。
判定這個變量的類型是啥
類型斷言不是類型轉換
兩種寫法
<類型>值
or值 as 類型
若是在 tsx 語法中使用,必須用
as
聯合類型能夠指定一個變量爲多種類型,此變量只能訪問類型們的共有方法。
但一些狀況下咱們必須使用某一類型的方法或屬性時,就能夠用斷言
function say(something:number|string):void{
alert(something.length) // 聯合類型,報錯
}
// ==> 使用斷言, 在變量前加上 <類型>
function say(something:number|string):void{
alert( (<string>something).length ) // success } 複製代碼
斷言成一個聯合類型中不存在的類型是不容許的
function say(something:number|string):void{
alert(<boolean>something.length) // 聯合類型沒有 boolean ,error } 複製代碼
第三方庫會暴露出一個變量,讓咱們在項目中直接使用。
可是 ts 編譯時不知道這是啥,編譯沒法經過。
此時咱們就要用
declare var
聲明語句來定義他的類型
// 好比 jquery
$('div') // ERROR: Cannot find name 'jQuery'.
// ==> 使用 declare var 第三方庫變量: (參數: string) => 返回類型
declare var $: (selector: string) => any;
$('#foo'); // success
複製代碼
declare var
並非真正的聲明一個變量,編譯完會刪除,僅僅是定義類型。
一般咱們會把聲明語句放到一個單獨的文件(
*.d.ts
)中,這就是聲明文件聲明文件必需以
.d.ts
爲後綴假如仍然沒法解析,那麼能夠檢查下
tsconfig.json
中的files
、include
和exclude
配置,確保其包含了jQuery.d.ts
文件。
// src/jQuery.d.ts
declare var jQuery: (selector: string) => any;
複製代碼
這只是非模塊化項目中使用的例子
固然,jQuery 的聲明文件不須要咱們定義了,社區已經幫咱們定義好了:jQuery in DefinitelyTyped。
咱們能夠直接下載下來使用,可是更推薦的是使用 @types
統一管理第三方庫的聲明文件。
@types
的使用方式很簡單,直接用 npm 安裝對應的聲明模塊便可,以 jQuery 舉例:
npm i @types/jquery -D
複製代碼
能夠在這個頁面搜索你須要的聲明文件。
聲明文件有如下方法
- 全局變量:經過
<script>
標籤引入第三方庫,注入全局變量- npm 包:經過
import foo from 'foo'
導入,符合 ES6 模塊規範- UMD 庫:既能夠經過
<script>
標籤引入,又能夠經過import
導入- 模塊插件:經過
import
導入後,能夠改變另外一個模塊的結構- 直接擴展全局變量:經過
<script>
標籤引入後,改變一個全局變量的結構。好比爲String.prototype
新增了一個方法- 經過導入擴展全局變量:經過
import
導入後,能夠改變一個全局變量的結構這裏只記錄 npm 導入的方法, 其餘請看 書寫聲明文件
在給一個第三方庫寫聲明文件以前,先查看這個庫有沒有聲明文件。通常來講,npm 包的聲明文件可能存在於兩個地方:
package.json
中有type
字段,或者有 index.d.ts
聲明文件。通常經常使用的包都有了,本身要發佈 npm 包的時候最好也綁定在一塊兒。npm install @types/foo --save-dev
直接經過安裝。若是都沒有,才本身寫。
聲明文件存放的位置是有約束的,通常在兩個位置。
node_modules
建立第三方庫的聲明文件,但這種通常不採納。通常 node_modules
不會隨咱們的應用發佈到服務器|git上。types
目錄來寫,要配合tsconfig.json
來使用。# 項目結構
├── README.md
├── src
| └── index.ts
├── types
| └── foo
| └── index.d.ts
└── tsconfig.json
複製代碼
{
"compilerOptions": {
"module": "commonjs",
"baseUrl": "./",
"paths": {
"*" : ["types/*"]
}
}
}
複製代碼
無論採用了以上兩種方式中的哪種,我都強烈建議你們將書寫好的聲明文件(經過給原做者發 pr,或者直接提交到
@types
裏)發佈到開源社區中,享受了這麼多社區的優秀的資源,就應該在力所能及的時候給出一些回饋。只有全部人都參與進來,才能讓 ts 社區更加繁榮。
npm 包寫的聲明文件 declare
不會聲明一個全局變量,只有導出的時候纔會應用類型聲明。
export const name: string; // 簡單類型
export function getName(): string; // 函數 export class Animal { // class 聲明
constructor(name: string);
sayHi(): string;
}
export interface Options { // 接口
data: any;
}
// ===> 對應使用到項目中
import { name, getName, Animal, Directions, Options } from 'foo';
let myName = getName();
let cat = new Animal('Tom');
let options: Options = {
data: {
name: 'foo'
}
}
複製代碼
declare
export
經過 declare 定義多個變量,一次性導出
declare const name: string;
declare function getName(): string; declare class Animal {
constructor(name: string);
sayHi(): string;
}
export {
name,
getName,
Animal,
}
複製代碼
只有
function
、class
和interface
能夠直接默認導出,其餘的變量須要先定義出來,再默認導出針對默認導出,通常會把導出語句煩惱歌在聲明文件的最前面。
export default function foo(): string; export default interface Options {
data: any
}
export default class Person {
constructor(name: string);
sayHi(): string;
}
declare const str:string;
export default str;
複製代碼
export namespace
namespace
原本是 TS 的模塊化方案,隨着 es6愈來愈屌基本已經不在 ts 中使用了。可是聲明文件中仍是很經常使用的,表示變量是一個包含了子屬性的對象類型。
像是
lodash
,它是個對象,但提供了不少子屬性方法如lodash.debunce
若是對象擁有深層的層級,則須要用嵌套的
namespace
來聲明深層的屬性的類型:總的來講,用來導出一個擁有子屬性的對象。
export namespace obj {
const name: string;
function fn(a:string,b?:nnumber):void; class Event {
say(str:string):void
};
// 若是還有包含子屬性的對象,就嵌套
namespace sonObj {
const foo: string;
}
}
複製代碼
當一個變量,既是函數又是對象。能夠組合多個語句聲明。
export function objAndFn(foo:string):any; export namespace objAndFn {
function fn(boo:number):void; const name:string; } 複製代碼
commonjs
規範用如下方式來導出:
// 總體導出
module.exports = foo;
// 單個導出
exports.bar = bar;
複製代碼
在 ts 中,針對這種導出,有多種方式能夠導入,第一種方式是 const ... = require
:
// 總體導入
const foo = require('foo');
// 單個導入
const bar = require('foo').bar;
複製代碼
第二種方式是 import ... from
,注意針對總體導出,須要使用 import * as
來導入:
// 總體導入
import * as foo from 'foo';
// 單個導入
import { bar } from 'foo';
複製代碼
第三種方式是 import ... require
,這也是 ts 官方推薦的方式:
// 總體導入
import foo = require('foo');
// 單個導入
import bar = require('foo').bar;
複製代碼
對於 commonjs
規範的庫,須要使用 export = 變量
的語法寫聲明文件
準確地講,export =
不只能夠用在聲明文件中,也能夠用在普通的 ts 文件中。實際上,import ... require
和 export =
都是 ts 爲了兼容 AMD 規範和 commonjs 規範而創立的新語法
export = foo;
declare function foo():string; declare namespace foo {
const bar: nnumber;
}
複製代碼
TS定義了 js 中內置對象的類型,在 TypeScript 核心庫的定義文件中。
包括 ECMAscript、DOM、Bom 等
這些內置對象的類型在
.ts
中均可以直接使用
let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred');
let d: Date = new Date();
let r: RegExp = /[a-z]/;
let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) {
// Do something
});
複製代碼
還會在該內置對象中定位錯誤
Math.pow(10, '2'); // error 必須是兩個 number 型
document.addEventListener('click', function(e) {
console.log(e.targetCurrent);
// error, MouseEvent 類型不存在 targetCurrent屬性
});
複製代碼
內置對象不包含 Node ,若是要使用
npm install @types/node --save-dev
複製代碼
這章是介紹面向對象編程
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
console.log(this.greeting); // world
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
複製代碼
基本繼承 做爲基類的類通常被叫作超類,繼承的類叫作派生類
class Car {
name: string = '大衆';
by() {
console.log(this.name);
}
}
class Baoma extends Car {
name: string = '寶馬'
}
let bm = new Baoma()
bm.by()
複製代碼
在子類
constructor
構造函數中***必須調用一下super***,它會執行基類的構造函數 在子類constructor
構造函數調用this以前必須先調用super
class FClass {
name: string = '超類'
constructor(name: string) { this.name = name; }
setAge(age:number) {
console.log(`${this.name} is ${age}`);
}
}
class SClass extends FClass {
constructor(name:string) {
super(name)
}
}
let f = new SClass('zzc')
f.setAge(20)
複製代碼
public
能夠被除本身以外的因此子類訪問到 ts中全部成員默認爲public
當一個成員被標記成private
時,沒法被外部訪問 若是類的constructor
聲明成了private
那就沒辦法new
和繼承了。protected
受保護的,跟private
基本同樣,但它在子類中能夠訪問;
class FClass {
name: string = '超類'
private constructor(name: string) { this.name = name; }
setAge(age:number) {
console.log(`${this.name} is ${age}`);
}
}
let f = new FClass() // error
class Son extends FClass {} // error
複製代碼
protected 受保護的例子
class F {
protected name: string;
constructor(name: string) { this.name = name; }
setAge(age:number) {
console.log(`${this.name} is ${age}`);
}
}
class Son extends F {
constructor() {
super('son')
}
getName() {
super.name // 能夠在子類訪問
}
}
let f = new F('super class')
let s = new Son()
console.log(s.name); // 不能在外部訪問
console.log(s.getName()); // 但能夠經過子類的方法return出來獲取到
複製代碼
在類中或者
constructor
都還能夠更改readonly
的值,但在外部就沒法更改了。
class F {
readonly a:number = 8
constructor(age:number) {
this.a = age
}
}
let f = new F(9)
f.a = 10 // error 沒法在外部更改
複製代碼
在
constructor
用一句話定義並賦值一個屬性 只要在參數前面加了訪問限定符就能夠直接給一個屬性直接賦值readonly
protected
public
private
static
是私有的,因此不能加。
class F {
readonly a:number = 8
constructor(readonly b:number) {
b = 10
}
}
let f = new F(9)
console.log(f); // {a,b}
複製代碼
當一個屬性只有get方法的時候,它就是隻讀的。 這也是一種外部改變靜態屬性的方法
// 當a = 'a' 時,內部的_a纔會等於賦的值,不然報錯。
class F {
private _a:string;
get a():string {
return this._a
}
set a(newA:string) {
if(newA === 'a') {
this._a = newA
}
else {
this._a = 'error'
}
}
}
let f = new F()
f.a = 'b'
console.log(f);
複製代碼
它只掛在class自己,而不是經過new實例化後出來的對象 因此你能夠經過
類.static屬性
來調用,但不能用this
class F {
static num: number;
changeStatic() {
F.num = 19;
}
constructor () {
this.changeStatic()
console.log(F.num);
}
}
let f = new F();
複製代碼
abstract
用來定義抽象類 和 在抽象類中定義抽象方法的 抽象類就是派生類的一個模板類,通常不會把它實例化,只是給子類繼承用的。
abstract class Animal { // 抽象一個Animal類
abstract makeSound(): void; // 抽象一個方法,必須在子類實現它
move(): void {
console.log('roaming the earch...');
}
constructor () {
}
}
class Son extends Animal {
constructor() {
super()
}
makeSound() { // 必須實現抽象類中的方法
return false
}
haha() {
console.log('error');
}
}
let s:Animal // 能夠指定抽象類爲一個類型
s.haha() // 若是上面的聲明瞭,那麼調用抽象類中不存在的haha方法是不容許
s = new Animal() // 不能夠new 抽象類
s = new Son() // 正確
s.makeSound() // 正確
複製代碼
若是沒有明確的指定類型,那麼 TypeScript 會依照類型推論(Type Inference)的規則推斷出一個類型。
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7; // error
// 等價於 ==>
let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;
複製代碼
若是定義的時候沒有賦值,無論以後有沒有賦值,都會被推斷成 any 類型而徹底不被類型檢查:
let myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
複製代碼
表示變量能夠是多種類型其中的一種
經過
|
分隔
let numOrStr : string | number;
numOrStr = 7;
numOrStr = '7';
numOrStr = true; // false
複製代碼
當調用聯合類型的方法時,只能調用倆類型中共有的方法。
let numOrStr : string | number;
numOrStr.length // 報錯 length 不是 number 的方法
numOrStr.toString() // 能夠
複製代碼