1.ts介紹
微軟開發的開源編程語言,是js的超集。
2.安裝
yarn global add typescript
3.運行
編譯ts文件
tsc index.ts
初始化配置文件
tsc --init
會生成tsconfig.json文件
4.ts中的數據類型
布爾類型(boolean)
數字類型 (number)
字符串類型 (string)
數組類型 (array)
元組類型 (tuple)
枚舉類型(enum)
任意類型(any)
unknown
null和undefined
void類型
never類型
- 布爾類型,數字類型,字符串類型
let bol:boolean=true; //只能是true或者false
let bol1:boolean=undefined; // error
let str:string=""; // 只能是字符串
let str1:string="aa"; // 只能是字符串
let num: number=1;//整數可以
let num1:number=1.12; //浮點數可以
let num2:number=NaN;//NaN可以
- 數組類型
let arr:number[]=[1,2,3,4]// 純數字數組
let arr2:string[]=['1','2']// 純字符串數組
let arr3:string[]=[]// 允許是空數組
arr3.push("123")// ok
arr3.push(123)// error 數組只能包含字符串
let arr4:any[]=[1,false,'haha'];//任意類型填充的數組用any
數組的另一種表示方法
let arr5:Array<string>=['hahah'];
let arr6:Array<number>=[1,2,3];
。。。
- 元組類型tuple(數組的一種)
個數、類型必須嚴格遵守
let arr:[string,number]=['haha',12];
let arr1:[string,number]=['haha'];//error
let arr2:[string,number]=['haha',12,1];//error
- 枚舉類型(enum)
提升代碼的可讀性,可用于將狀態碼映射成數字
enum Flag {
success=1,
error=-1
}
let f:Flag=Flag.success; //1
Flag.success //1
Flag.error // -1
沒有賦值的情況
enum Color {
red,
blue,
orange=10,
black,
}
//如果沒有賦值就取自己的索引,如果有值就取值,后邊的是前邊的值+1
Color.red // 0
Color.blue // 1
Color.orange // 10
Color.black // 11
- 任意類型 any
let n:any=123;//可以賦任何值
n='haha';
n=false;
n.foo.bar; // OK 不進行驗證
n.trim(); // OK 不進行驗證
let arr:any[]=[1,false,'haha']//可以是任何類型
- unknown類型
// unkonwn 類型只能被賦值給any和unknown本身 只有能保存任意類型值的容器才能保存unknown本身
let u: unknown = 123;
u='aaa';
let a: string = u; // not ok;
- null和undefined
let un:undefined;
console.log(un)//輸出undefined
//“或者”用“ | ”表示
let un2:number | undefined | string | null;
un2=11;
console.log(un2);//11
let un3:null;
console.log(un3)//error 因為是undefined
let un4:null;
un4=null
console.log(un4)//null
let un5:null=null;
console.log(un5)//null
- void類型:ts中的void表示沒有任何類型,一般用于定義的方法沒有返回值
function fn():void{
console.log(1)
}
fn()//1
function fn2():void{
console.log(1)
return 1
}
//error
- never類型
var a:never;
a=(()=>{
throw new Error('錯誤');
})()
5.函數的寫法
//設置返回值必須是字符串
function run():string{
return 'haha';
}
let run2=function():string{
return 'haha';
}
//設置函數參數的類型
let run3=function(name:string,age:number):string{
return `${name}---${age}`;
}
run3('ts',20)// 'ts---20'
//沒有返回值的函數
let run4=function(name:string,age:number):void{
console.log( `${name}---${age}`)
}
run4('ts',20)// 'ts---20'
//可選參數 " ? " 表示,可選參數必須配置到參數的最后面
let run5=function(name:string,age?:number):string{
if(age){
return `${name}---${age}`
}else{
return `${name}---空`
}
run5('ts',20)// 'ts---20'
run5('ts')// 'ts---空'
//默認參數
let run6=function(name:string,age:number=10):void{
console.log( `${name}---${age}`)
}
run6('ts',20)// 'ts---20'
run6('ts')// 'ts---10'
//剩余參數
function sum(a:number,b:number,c:number):number{
return a+b+c
}
sum(1,2,3)//6
function sum2(...res:number[]):number{
return res.reduce((prev,next)=>{
return prev+next
},0)
}
sum2(1,2,3)//6
function sum4(a:number,...res:number[]):number{
return res.reduce((prev,next)=>{
return prev+next
},a)
}
sum4(1,2,3)//6
//ts函數的重載(重載指的是兩個或者以上的同名函數,但他們參數不一樣,這是會出現重載的情況)
function getInfo(name:string):string
function getInfo(age:number):string
function getInfo(str:any):any{
if(typeof str==='string'){
return `name-${str}`
}else{
return `age-${str}`
}
}
getInfo('zhang')// name-zhang
getInfo(12)// age-12
//箭頭函數 和以上規則一致
var fun3 = (a:number, b:number):number=>{
return a+b;
}
- ts中的類class
class Person{
name:string;
constructor(n:string){
this.name=n;
}
run():void{
alert(this.name);
}
work():string{
return this.name;
}
}
var p=new Person('張三');
p.run();//張三
//類的繼承
class Workers extends Person{
constructor(name:string){
super(name);
}
}
let work = new Workers('里斯');//里斯
work.run()
//類里邊的修飾符 ts里邊定義屬性的時候提供了三個修飾符
//public公有的 :< 在類里邊、子類、類外邊都可以訪問 >
//protected受保護的 : < 在類里邊、子類里邊可以訪問、在類外部沒法訪問 >
//private私有的 : < 在類里可以訪問,子類、類外部都沒法訪問 >
//屬性如果不加修飾符默認是 public 公有的
class Person{
public name:string;//------可不寫public-------
constructor(n:string){
this.name=n;
}
run():string{
return this.name//類里邊訪問
}
}
var p=new Person('張三');
p.name;//類外邊訪問
class Workers extends Person{
constructor(name:string){
super(name);
}
work():void{
alert(this.name)//子類里邊訪問
}
}
//-----------protected受保護的-------------
class Person{
protected name:string;
constructor(n:string){
this.name=n;
}
run():string{
return this.name//類里邊訪問
}
}
var p=new Person('張三');
p.name;//-----------類外邊訪問 error---------
class Workers extends Person{
constructor(name:string){
super(name);
}
work():void{
alert(this.name)//子類里邊訪問
}
}
//---------------private--------------------
class Person{
private name:string;
constructor(n:string){
this.name=n;
}
run():string{
return this.name//類里邊訪問
}
}
var p=new Person('張三');
p.name;//-----------類外邊訪問 error-----------
class Workers extends Person{
constructor(name:string){
super(name);
}
work():void{
alert(this.name)//------子類里邊訪問 error-----------
}
}
//ts中的抽象類,他是提供繼承的基類,不能被直接實例化
//用abstract關鍵字定義抽象類和抽象方法,抽象類中的抽象方法不包含具體實現并且必須在派生類中實現
//abstract的抽象方法只能放到抽象類中
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:string){
super(name);
}
//**抽象類的子類必須實現抽象類里邊的抽象方法**
eat(){
console.log(this.name)
}
}
let d=new Dog('狗');
d.eat();
6.接口 interface
接口的作用:在面向對象的編程中,接口是一種規范的定義,它定義了行為和動作的規范,在程序設計里面,接口起到一種限制和規范的作用。接口定義了某一批所需要遵守的規范,接口不關心這些類內部狀態數據,也不關心類方法里的實現細節,他只規定這批類必須提供的某些方法,提供這些方法的類就可以滿足實際需要。
-
接口類型:
屬性類接口、函數類型接口、可索引接口、類類型接口、接口拓展1.屬性類接口 對json的約束
function fn1(obj:{name:string}):void{ console.log(obj.name) } fn1({name:'hello'})// hello fn1({name:123})// error fn1({name:'hello',age:2})// error //interface寫法 對批量方法傳入參數都進行約束 interface FullName{ firstName:string; //注意‘ ; ’結束 lastName:string; }; function fn2(obj:FullName):string{ return obj.firstName+obj.lastName; } fn2({firstName:'hello',lastName:'ts'});//必須只包括著兩個屬性 fn2({firstName:'hello',lastName:'ts',age:12});// error let obj={ firstName:'hello', lastName:'ts', age:12 } fn2(obj);//這樣傳入的obj只要包含兩個屬性即可,但是函數內不允許使用age屬性 //可選屬性接口 interface FullName{ firstName:string; //注意‘ ; ’結束 lastName?:string; }; //可以這么用 fn2({firstName:'aaa'}); fn2({firstName:'aaa',lastName:'bbb'});
2.函數類型接口:對方法傳入的參數 以及返回值進行約束
interface encrypt{ (key:string,value:string):string } let md5:encrypt=function(key:string,value:string):string{ return key+value; } // 或這樣寫 let md6:encrypt=function(key,value){ return key+value; }
- 可索引接口: 對數組、對象的約束(不常用)
// let arr:number[]=[1,2,3];//數組類型 // 對數組的約束 interface UserArr{ [index:number]:string// index屬性是number類型,值是string類型 } let arr:UserArr=['1','2'] // 對對象的約束 interface UserArr{ [index:string]:string// index屬性是string類型,值是string類型 } let obj:UserArr={name:'aaa'}
- 類類型接口(implements) 和抽象類相似
interface Animal{ name:string; eat(str:string):void; } // Dog必須包含name和eat class Dog implements Animal{ name:string; constructor(name:string){ this.name=name; } eat(str:string):void{ console.log(this.name+str) }; run(str:string):void{ console.log('run'); } } let d=new Dog('小黑'); d.eat('古,頭')
- 接口擴展,接口可以繼承接口
interface Animal1{ eat():void; } interface Person1 extends Animal1{ work():void; } class Web1 implements Person1{ constructor(){/**do some**/} eat(){/**do some**/}; work(){/**do some**/} } let w=new Web1(); class Pro{ public name:string; constructor(name:string){ this.name=name; } coding(code:string):void{ console.log(this.name+code) } //add eat ,Web2就可以不用再定義eat eat(){}; } class Web2 extends Pro implements Person1{ constructor(name:string){ super(name) } // eat(){}; work(){} } let w2=new Web2('123');
type類型別名
- 類型別名會給一個類型起個新名字。 類型別名有時和接口interface很像,但是可以作用于原始值,聯合類型,元組以及其它任何你需要手寫的類型。
- 可以使用 &交叉類型 和 |聯合類型。
- 不能使用extends和implements
interface定義一個實實在在的接口,是一個真正的類型 / type一般指一個別名,不會產生真實的類型。
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
type Container<T> = { value: T };
7.泛型<T>
為了組件的靈活性,組件不僅能夠支持當前的數據類型,同時也應該能支持未來的數據類型,,一個組件可以支持多種數據類型。這樣用戶就可以以自己的數據類型來使用組件。
泛型就是解決 類、接口、方法的復用性、以及對不特定的數據類型的支持(類型校驗)
- 泛型函數
// any可以解決問題,它放棄了類型檢查
// 泛型:可以支持不特定的數據類型,要求傳入的參數和返回的參數一致
function getData<T>(value:T):T{// T表示泛型,具體什么類型是調用這個方法的時候決定的
return value
}
getData<number>(123);//參數必須是number
getData<string>('123');//參數必須是string
getData<number>('aaa'); // error
- 泛型類
class MinClass<T>{
public list:T[]=[];
add(value:T):void{
this.list.push(value);
}
min():T{
let min=this.list[0];
for(let i=0;i<this.list.length;i++){
if(min>this.list[i]){min=this.list[i]}
}
return min;
}
}
let m1=new MinClass<number>()//傳入的參數只能是number
//實例化類,并且制定了類的T代表的類型是number
m1.add(2);
m1.add(1);
m1.add(3);
m1.min();
react中使用泛型
type Props = {
className?: string
...
};
type State = {
submitted?: bool
...
};
class MyComponent extends React.Component<Props, State> {
...
}
- 泛型接口
interface ConfigFn{
<T>(value:T):T
}
let getDate:ConfigFn=function<T>(value:T):T{
return value;
}
getDate<string>('值value')
//另一種寫法
interface ConfigFn<T>{
(value:T):T
}
function getData3<T>(value:T):T{
return value;
}
var myGetData:ConfigFn<string> = getData3;
myGetData('值value')
myGetData(20)// REEOR
- 泛類
泛型可以幫助我們避免重復的代碼以及對不特定數據類型的支持
- 定義個類;
- 把類作為參數來約束數據傳入的類型
//操作數據庫的泛型類
class MysqlDb<T>{
add(info:T):boolean{
console.log(info);
return true;
}
}
//1.定義一個user類,和數據庫進行映射
class User{
username:string|undefined;
pasword:string|undefined;
}
let u=new User();
u.username='haha';
u.pasword="1234";
let Db=new MysqlDb();
Db.add(u);
symbols 和es6的一致 一種新的數據額類型
let sym2 = Symbol("key");
let sym3 = Symbol("key");
sym2 === sym3; // false, symbols是唯一的
//像字符串一樣,symbols也可以被用做對象屬性的鍵。
let sym = Symbol();
let obj = {
[sym]: "value"
};
console.log(obj[sym]); // "value"
// Symbols也可以與計算出的屬性名聲明相結合來聲明對象的屬性和類成員
const getClassNameSymbol = Symbol();
class C {
[getClassNameSymbol](){
return "C";
}
}
let c = new C();
let className = c[getClassNameSymbol](); // "C"
命名空間 namespace
// 相當于一個自執行函數
//定義一個namespace 暴露里邊的變量、函數等數據需要使用export導出,不導出的外部無法使用
namespace Validation {
export interface StringValidator {//暴露類類型接口
isAcceptable(s: string): boolean;
}
const lettersRegexp = /^[A-Za-z]+$/;
const numberRegexp = /^[0-9]+$/;
export class LettersOnlyValidator implements StringValidator {//暴露一個類
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
export class ZipCodeValidator implements StringValidator {//暴露一個類
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
}
new Validation.LettersOnlyValidator().isAcceptable("123");
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
聲明合并
//1.合并接口
// 同名接口會合并、
// 同屬性接口必須類型一致、
// 接口定義會被提升,合并也會被提前編譯、
// 使用合并后的接口必須包含所有的屬性、
interface Box {
height: number;
width: number;
}
let box1: Box = {height: 5, width: 6};//報錯 跟代碼順序無關
interface Box {
height: number;
width: string;//同名屬性,類型不一樣,合并會報錯
scale: number;
}
let box: Box = {height: 5, width: 6, scale: 10};
let box2: Box = {height: 5, width: 6};//報錯 必須包含合并后接口的所有屬性
對于函數類型接口,每個同名函數聲明都會被當成這個函數的一個重載。 同時需要注意,當接口 A與后來的接口 A合并時,后面的接口具有更高的優先級。
裝飾器decorators
能夠被附加到類聲明、方法、屬性、參數上
//裝飾器
function sealed(target) {
// target就是被裝飾的函數、類或者其他
}
@sealed
XXX類{
xxx
}
//等價于sealed(XXX類)
//裝飾器工廠
function color(value: string) { // 這是一個裝飾器工廠
return function (target) { // 這是裝飾器
// do something with "target" and "value"...
}
}
@color('res')
XXX類{
xxx
}
//等價于color('red')(XXX類)
//分類
//1.類裝飾器
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
function sealed(constructor: Function) {
console.log(constructor)//Greeter
}
//2.方法裝飾器
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@sealed
greet() {
return "Hello, " + this.greeting;
}
}
function sealed(target,fnName,desc) {
console.log(target)//函數本身
console.log(fnName)//函數名
console.log(desc)//函數描述
}
//3.屬性裝飾器
class Greeter {
@sealed
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
function sealed(target,attr) {
console.log(target)//實例對象
console.log(attr)//屬性名
}
//4.參數裝飾器
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet(@sealed g:string) {
return g + this.greeting;
}
}
function sealed(target,fnName,index) {
console.log(target)//實例對象
console.log(fnName)//函數名
console.log(index)//當前參數的索引
}