typescript学习笔记(一)

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;
     }
    
    
    1. 可索引接口: 对数组、对象的约束(不常用)
     // 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'}
    
    1. 类类型接口(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('古,头')
    
    1. 接口扩展,接口可以继承接口
    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
  • 泛类
    泛型可以帮助我们避免重复的代码以及对不特定数据类型的支持
  1. 定义个类;
  2. 把类作为参数来约束数据传入的类型
//操作数据库的泛型类
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)//当前参数的索引
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335