TypeScript总结

565 阅读11分钟

启动

  1. 使用npm install typescript -S命令下载依赖包
  2. 使用tsc --init 生成tsconfig.json配置文件
  3. 在package.json文件中添加
 "scripts":{
    "build":"tsc",
    "dev":"tsc --watch"
  }
  1. 使用npm run dev 启动ts编译js的监控

基本类型

1.基本写法

let zname:string = 'hello';
let age:number =10;
let married:boolean = true;
let hobbies:number[] = [1,2,3];
let arr2:Array<number> = [4,5,6];

2.元组

let zhufeng:[string,number] = ['zhufeng',10];
let point:[number,number] = [10,10];

3.枚举

enum Gender{
  BOY,
  GIRL
}
let g1:Gender = Gender.BOY;
let g2:Gender = Gender.GIRL;
console.log(Gender);
console.log(g1); //0
console.log(g2); //1

const enum Color{
  RED=1,
  YELLOW,
  BLUE,
}
console.log(Color.RED,Color.YELLOW,Color.BLUE);

4.any类型

let zname:any = 10;
zname = 'hello';
zname = 'true';
zname = null;
zname = undefined;

5.联合类型

// nudefined null 是 number的子类型, 方法:修改strictNullChecks=false,或者定义联合类型
let x:number|undefined|null;
x = 10;
x = undefined;
x = null;

6.void类型

//void 表示没有任何类型
function greeting(name:string):void{
  return undefined;
}

7.never类型

//never 永远不知道什么类型
//一个函数永远不会返回,那么他的返回值类型就是never
function sum():never{
  while(true){

  }
}
//如果函数一定要抛出错误,那么他也永远不会正常结束,他的返回类型也是never
function minis():never{
  throw Error('我错了');
}

function double(x:number|string){
  if(typeof x=='number'){
    console.log(x);
  }else if(typeof x == 'string'){
    console.log(x);
  }else{
    console.log(x);
  }
}

基本类型-额外补充

// 1.!符号
对于可能为null的变量,使用!取消提示
let root:(HTMLElement|null) = document.getElementById('root');
root!.style.color = 'red';

 let root:any = document.getElementById('root');
 root.style.color = 'red';
 
 // 2.自动装箱
 let x = 'hello';
//js中有一个自动装箱的过程,如果对一个基本类型调用方法,
//他会在内部迅速做一次包装,把这个基本类型包装成对象类型,然后就可以调用方法
console.log(x.toLowerCase());
console.log(new String(x).toLowerCase());//这是内部实现的

// 3.类型断言
let znames:number|string|null;
 znames = 'hello';
 console.log(znames.length);
// znames = 10;
// console.log(znames.toFixed());
//断言,我强行告诉ts是一个什么类型
 console.log((znames as string).length);
// console.log((znames as number).toFixed);、

//ps. let names : 1|2|'a'|'b' = 1;

函数

函数定义

function hello(name:string):string{
  return 'hello'+name;
}

函数表达式

//定义一个类型,用来约束一个函数表达式,参数有两个firstname,lastname返回一个字符串
//不是箭头函数,只是有点像,箭头用来做分割
type GetFunction =(x:string,y:string)=>string;
let getUsername:GetFunction = function(firstname:string,lastname:string):string{
  return firstname + lastname;
}

函数的重载

//方法名一样,参数的数量或类型不一样
//在TS里,仅仅指是为了一个函数提供多个函数定义
let obj = {name:'zhufeng',age:10};
function attr(val:string):void;
function attr(val:number):void;
function attr(val:any){
  if(typeof val === 'string'){
    obj.name = val;
  }else if (typeof val == 'number'){
    obj.age = val;
  }
}
attr('obj');
attr(20);
// attr(true);
console.log(obj);

函数-额外补充

// 1. ? 可选参数
function print(name:string,age?:number):void{
  console.log(name,age);
}
print('zhufeng',10);

// 2. 默认参数
function ajax(url:string,method:string="get") {
  console.log(url,method);
}
ajax("/user")

// 3. 剩余参数
function sum(...numbers:number[]){
  console.log(numbers);
}
sum(1,2,3);

基本写法

class Person{
  name:string;
  constructor(name:string){
    this.name = name;
  }
  getName():void{
    console.log(this.name);
  }
}

class User{
  myname:string;
  constructor(myname:string){
    this.myname = myname;
  }
  get name(){
    return this.myname;
  }
  set name(newName:string){
    this.myname = newName;
  }
}
let u = new User('a');
console.log(u.name);//a
u.name = 'b';
console.log(u.name);//b

console.log(u.hasOwnProperty('name'));//false
console.log(Object.getPrototypeOf(u).hasOwnProperty('name'));//true
console.dir(User);//[Function:User]
console.dir(u);//User {myname:'b'}

访问修饰符

//通过类型的继承来讲一下访问修饰符 public protected private
//public 公开的,里里外外都能访问 自己 自己的子类 其他类都能访问
//protected 受保护的,自己和子类能访问,其他地方不能访问
//private 私有的,只能自己访问,子类和其他都不能访问
//abstract类 不能被实例化new 只能被继承
 class Animal{
  public readonly name:string;
  protected age:number = 18;
  private money:number = 10;
  constructor(name:string){
    this.name = name;
  }
}


//abstract 抽象类一般是用来封装一些公共的,给子类使用的方法属性
class Dog extends Animal{
  static className = 'Dog';
  static getClassName(){
    console.log(Dog.className);
  }
  getName(){
    console.log(this.name);
  }
  getAge(){
    console.log(this.age);
  }
  getMoney(){
    // console.log(this.money);

  }
}
let a = new Animal('zhufeng');
a.name;
// a.age;
// a.money

抽象类和接口->继承,重写

//1.抽象类是行为的抽象,一般来封装一些公共的属性的方法的,不能被实例化
abstract class Animal {
  name:string;
  constructor(name:string){
    this.name = name;
  }
  abstract speak():void;
}

//接口里的方法都是抽象的
interface Flying{
  fly():void;
}
interface Eating{
  eat():void;
}
class Dog extends Animal{
  speak(){
    console.log('汪汪汪');
  }
}
//子类重写继承自父类种的方法 重写
class Cat extends Animal implements Flying,Eating{
  speak(){
    console.log('喵喵喵!');
  }
  fly(){
    console.log('我是一只飞猫');
  }
  eat(){
    console.log('我是一只吃猫');
  }
}
let cat = new Cat('cat');
cat.speak();
cat.name;

接口

接口表示对象的形状

interface Speakable{
  speak?():void;
  name:string;
}
let speaker:Speakable = {
  name:'zhufeng',
  speak(){}
}
interface Rectangle{
  width:number;
  height:number;
}

let r:Rectangle = {
  width:10,
  height:20
}

接口用来描述行为的抽象

interface AnimalLike{
  eat():void;
  move():void;
}

interface PersonLike extends AnimalLike{
  speak():void;
}

class Girl implements PersonLike{
  eat(){};
  move(){};
  speak(){};
}

接口类型必要属性和可选属性

interface Person{
  readonly id:number;
  name:string;
  [propName:string]:any;//任意属性
}

let p2:Person = {
  id:1,
  name:'zhufeng',
  age:10,
  home:'北京'
}

用接口规范或定义函数

interface DiscountInterface{
  (price:number):number
}
let discount:DiscountInterface = function(price:number):number{
  return price*.8;
}
interface SumInterface{
  ():number;//sum
}
let sum:SumInterface= function():number{
  let args:IArguments = arguments;
  return Array.prototype.slice.call(args).reduce((val,item)=>val+item,0);
}

interface SumInterface{
  (...args:any[]):number;//sum3
}
let sum2:SumInterface= function(...args:number[]):number{
  return args.reduce((val,item)=>val+item,0);
}
console.log(sum2(1,2,3))

可索引接口,对数组或对象进行约束

interface UserInterface{
  [index:number]:string
}
let arr:UserInterface = ['zf','jg'];
console.log(arr);

interface UserInterface2{
  [index:string]:string
}
let obj2:UserInterface2 = {name:'zhufeng'}

类的接口,用接口约束构造函数的类型

class Animal{
  constructor(public name:string){}
  static age:number; //类的属性
  static getAge(){}
}
class Desk{
  constructor(public price:number){}
}
let a3 = new Animal('zhufeng');
console.log(a3);
interface WithNameClass{
  new(name:string):Animal; //类的构造函数是类的属性
  age:number; 
  getAge():void
}
function createClass(clazz:WithNameClass,name:string){
  return new clazz(name);
}
let a4 = createClass(Animal,'zhufeng');
console.log(a4);

// let a5 = createClass(Desk,'jiagou');
// console.log(a5);

泛型

泛型函数

function createArray<T>(length:number,value:T):T[]{
  let arr:T[] = [];
  for(let i=0;i<length;i++){
    // @ts-ignore
    arr[i] = value;
  }
  return arr;
}
let arr = createArray<string>(3,'x');
console.log(arr); //['x','x','x']

泛型类

class MyArray<T>{
  constructor(private list:T[]){}
  add(element:T){
    this.list.push(element);
  }
  getMax():T{
    let maxVal = this.list[0];
    for(let i=1;i<this.list.length;i++){
      if(this.list[i]>maxVal){
        maxVal = this.list[i];
      }
    }
    return maxVal;
  }
}
let arr2 = new MyArray<number>([]);
arr2.add(1);
arr2.add(2);
arr2.add(3);
console.log(arr2.getMax());

泛型接口

//可以用来约束函数
interface Calculate{
  <T>(a:T,b:T):T

}
let add:Calculate = function(a,b){
  return a;
}
console.log(add<string>('ds','dsf'));

//在定义接口的时候也可以指定泛型
interface Cart<T>{
  list:T[]
}
let cart:Cart<number> = {list:[1,2,3]};
//泛型的别名  type可以定义别名 小名
type Cart2<T> = {list:T[]} | T[];

let c1:Cart2<number> = {list:[1,2,3]};
let c2:Cart2<number> = [1,2,3];

多个泛型

function swap<A,B>(tuple:[A,B]):[B,A]{
  return [tuple[1],tuple[0]]
}
let ret = swap([1,'a']);
ret[0].toLowerCase();
ret[1].toFixed(2);

泛型继承,用来预先定义方法

interface LengthWise{
  length:number
}
function logger2<T extends LengthWise>(val:T){
  console.log(val.length);
}
logger2('hello');

兼容性

接口的兼容性

//接口的兼容性
interface Animal{
  name:string;
  age:number
}
interface Person{
  name:string;
  age:number;
  married:boolean
}
function getAnimalName(animal:Animal){
  return animal.name;
}
let p1:Person = {name:'zhufeng',age:10,married:true}

getAnimalName(p1);

基本类型的兼容性


//基本类型的兼容性检查
let num:string | number;
let str:string = 'zhufeng';
num = str;

let num2: {
  toString():string
}
let str2:string = 'jiagou';
num2 = str2;

class Animal{
  public name:string = 'zhufeng';
}
class Bird extends Animal{
  public age:number = 9;
}
class Something{
  public home:string = 'beijing';
  public age:number = 9;
  public name:string = 'zhufeng';
}
let a:Animal;
a = new Bird();
let b:Bird;
b = new Animal();

b = new Something();

接口的兼容性


//函数的兼容性
type sumFunction = (a:number,b:number)=>number;
let sum :sumFunction;
function fun1(a:number,b:number){
  return a+b;
}
sum = fun1;
function fun2(a:number){
  return a;
}
sum = fun2;

type logFunc = (a:number|string)=>void;
let log:logFunc;
function log1(a:number|string|boolean){

}
log = log1;
function log2(a:number){

}
// log = log2;//不能将类型“string | number”分配给类型“number”

泛型的兼容性


//泛型的兼容性
//接口内容为空就可以赋值,不为空就不能赋值
interface Empty<T>{
  name:T
}
let x:Empty<string> = {name:'zhufeng'};
let y:Empty<number> = {name:10};
// x = y;
// interface Empty{
//   name:string
// }
// interface Empty{
//   name:number
// }

枚举的兼容性


//枚举的兼容性
enum Colors{
  Red,
  Blue,
  Yellow
}
let c: Colors;
c = Colors.Red;//0
c = 0;

let num3:number;
num3 = Colors.Yellow;

类型保护

基本类型的类型保护


//更明确的判断某个分支作用域中的类型
//基本数据类型的类型保护
function double(input:string|number|boolean):number{
  if(typeof input === 'string'){
    return input.length;
  }else if(typeof input === 'number'){
    return parseInt(input.toFixed(2));
  }else{
    input.valueOf();
    return 0;
  }
}

类的类型保护

class Animal{
  public name:string='1';
}
class Bird extends Animal{
  public age:number = 1;
}
class Dog extends Animal{
  public legs:number = 2;
}
function getName(animal:Animal){
  if(animal instanceof Bird){
    console.log(animal.age);
  }else{
    console.log(animal.name);
  }
}
getName(new Animal());
getName(new Bird());
let obj = {name:'zhufeng',age:10};
getName(obj);

null的类型保护

//null保护 如果说开启了strictNullChecks选项的话,我们就不能直接调用可能为null的变量上的方法了
//1. 加!
//2. 加一个或判断
//3. 修改strictNullChecks
function getFirstLetter(str:string|null){
  function log(){-
    console.log(str!.trim());
  }
  str = str || '';//str肯定是有值的
  log();
  return str.charAt(0);
} 

可辨识的联合类型


//可辨识的联合类型
interface WarningButton{
  class:'warning';
  text1:'修改'
}
interface DangerButton{
  class:'danger';
  text2:'删除'
}
type Button = WarningButton | DangerButton;
function getText(button:Button){
  if(button.class === 'warning'){
    button.text1
  }else if(button.class === 'danger'){
    button.text2
  }
}

//in 运算符
interface Bird{
  swing:number;
  fly():void
}
interface Dog{
  leg:number;
  run():void
}
function getNumber(animal:Bird|Dog){
  if('swing' in animal){
    animal.fly();
  }else{
    animal.run(); 
  }
}

自定义的类型保护


//有些时候两个类型 ,没有共同属性,不同的取值,也没有可以区分的属性,类型也一样
//自定义的类型保护
interface Bird2{
  leg:number;
}
interface Dog2{
  leg:number;
}
function isBird2(x:Bird2|Dog2):x is Bird2{
  return x.leg == 2;
}
//类型保护是为了让你更具体的调用参数上的属性和方法
function getAnimal(x:Bird2|Dog2):string{
  if(isBird2(x)){
    return '鸟2'
  }else{
    return '狗2'
  }
}

交叉类型

interface Bird{
  name:string;
  fly():void
}
interface Person{
  age:number;
  talk():void
}
//交叉类型 ,把多个类型合并成一个大的总类型
type birdMan = Bird & Person;
let bm:birdMan = {name:'zhufeng',fly(){},age:10,talk(){}}

typeof


//typeof 用来获取一个变量的类型
//先定义类型再定义变量
// type Person2 = {
//   name:string;
//   age:number;
//   gender:number
// }
//先拿到一个对象,然后通过对象获取反推这个对象的类型
let p2 = {name:'',age:10,gender:0};
type Person2 = typeof p2;
let p22:Person2 = {name:'zhufeng',age:10,gender:0};

索引访问操作符


//索引访问操作符
interface Person3 {
  name:string;
  age:number;
  job:{
    name:string
  };
  interests:{name:string,level:number}[]
}
let FrontEndJob:Person3['job'] = {name:'frontEnd'};
let interests:Person3['interests'] = [{name:'打篮球',level:1},{name:'唱歌',level:2},];

索引类型查询操作符 keyof

//索引类型查询操作符  keyof
interface Person4{
  name:string;
  age:number;
  gender:number;
}
type PersonKey = keyof Person4;
function getValueByKey(p:Person4,key:PersonKey){
  return p[key];
}
let p1:Person4 = {name:'zhufeng',age:10,gender:0};
let val = getValueByKey(p1,'name');
console.log(val);
// let xxval = getValueByKey(p1,'xx');
// console.log(xxval);

映射类型


//映射类型
interface Person5{
  name:string;
  age:number;
  gender:'male'|'female';
}

//批量定义
// type Person5Search = {
//   [key in keyof Person5]?:Person5[key]
// }
let p5:Person5Search = {name:"zhufeng",age:10};
//内置的工具类型
type Partial<T> = {[P in keyof T]?: T[P]};
type Person5Search = Partial<Person5>

interface Person6{
  name?:string;
  age?:number;
  gender?:'male'|'female'
}
let p6:Person6 = {name:'zhufeng',age:10};
type Required<T> = {[P in keyof T]-?:T[P]};
type Person6Required = Required<Person6>;
let p66:Person6Required = {name:'zhufeng',age:10,gender:'male'};

Pick,ReadOnly


//ReadOnly
interface Person7{
  readonly name:string;
  age:number;
  gender:'male'|'female'
}
type ReadOnly<T> = {readonly [P in keyof T]:T[P]};
type Person7ReadOnly = ReadOnly<Person7>;
let p7:Person7ReadOnly = {name:'zhufeng',age:10,gender:'male'};
//p7.name='jiagou';
//Pick 捡的意思 从一个大类型中检出来若干个小类型
interface Person8{
  name:string;
  age:number;
  gender:'male'|'female'
}
type Pick<T,K extends keyof T> = {[P in K]:T[P]};
type PersonSub = Pick<Person8,'name'|'age'>;
let ps:PersonSub = {name:'zhufeng',age:10};

//T K P分别什么情况下使用
//T 泛型类 回传过来一个类型   Person8
//K keys  若干个key         'name'|'age'
//P 临时变量,指的是K里的每个元素  name

Extract和Exclude


//Exclude
type E = Exclude<string|number|boolean,string>;
let e1:E = 10;
let e2:E = true;
// let e3:E = 'x';

//Extract
type E2 = Extract<string|number|boolean,string>;
// let e12:E2 = 10;
// let e22:E2 = true;
let e32:E2 = 'x';

interface Face1{
  name:string;
  job:{
    name:string;
  }
}
interface Face2{
  name:string;
}
interface Face3{
  name:string;
}
//Extract
type E3 = Extract<Face1|Face2|Face3,Face1['job']>;
let e33:E3 = {name:'zhufeng'};

类型声明

//类型声明
//我们可以给js写类型声明文件,就可以在js中使用ts了


declare let name:string;
declare let age:number;
declare function getName():string;
declare class Animal{name:string}
interface Person{
  name:string
}
type student = {
  name:string
}
//外部枚举  声明在外部,是一个枚举
//外部枚举是使用declare enum定义的枚举
declare const enum Season{
  Spring,
  Summer,
  Autumn,
  Winter
}
let seasons = [
  Season.Spring,
  Season.Summer,
  Season.Autumn,
  Season.Winter,
]

命名空间

//namespace 命名空间是用来定义包含很多子属性的全局变量的
//如果说在html里通过cdn引用全局变量 jquery $ 全局变量
declare namespace ${
  function ajax(url:string,setting:any):void
  let name:string;
  namespace fn{
    function extend(object:any):void
  }
}
$.ajax("/users",{});
console.log($.name);
$.fn.extend({});

扩展全局变量

//如果扩展全局变量局部的变量类型
declare global{
  interface String{
    double():string;
  }
  interface Window{
    myname:string;
  }
}

String.prototype.double = function(){
  return this + this;
}
console.log('hello'.double());



console.log(window.myname);

export{}

//合并声明  同一个名称的两个独立声明会合并成一个单一声明
//class是一个类,类可以做为类型来使用
class Person12 {
  name: string = 'hello';
}
let p1:Person12;
//在此处Person12就是一个值了
let p2 = new Person12();

interface Person13 {
  name: string;
}
let p3:Person13;


类型合并

//类型合并 1.ts
interface Animal16 {
  age: number;
}
let a16:Animal16 = {name:'zhufeng',age:2}

//通过命名空间扩展函数
declare function jQuery2(selector:string):any;
declare namespace jQuery2{
  let name:string;
}
----------
//类型声明的合并 2.ts
interface Animal16 {
  name: string;
}

//通过命名空间扩展类
class Form{
  username:Form.Item = '';
  password:Form.Item = '';
}
namespace Form{
  export class Item { }
}

enum Color{
  red=1,
  yellow=2,
  blue=3,
}
namespace Color{
  export const green = 4;
  export const purple = 5; 
}
console.log(Color.purple);