typescript我的總結

Typescript

從本文你能瞭解到那些知識

  • 強類型和弱類型
  • 靜態類型和動態類型
  • JavaScript自有類型系統的問題
  • Flow靜態類型檢查方案
  • TypeScript 語言規範和基本使用

強類型與弱類型 (類型安全)

TypeScript 是一門基於 JavaScript 之上的編程語言,它重點解決了 JavaScript 語言自己類型系統不足的問題。javascript

強類型:具備類型約束 不容許隱式類型轉換 約束後,不符合類型的編譯階段就會報錯,而不是執行階段html

弱類型:不具備類型約束 容許隱式類型轉換java

靜態類型和動態類型

靜態類型 一個變量聲明時他的類型就是明確的,而且不可修改node

動態類型 運行階段才能夠明確變量類型,並且變量的類型隨時能夠改變git

js 弱類型產生的問題

const obj ={}
obj.foo()  //只有運行階段才發現錯誤

//若是錯誤放異步中,就會存有隱患
setTimeout(() => {
  obj.foo()
}, 1000000);
//類型不明確致使沒法肯定函數功能
function sum (a,b){
  return a+b
}

console.log(sum(1,2));
console.log(sum("100",100));

相比於弱類型,強類型的優點typescript

  • 錯誤更早的暴露
  • 代碼更智能,編碼更準確 根據強類型的智能提示
  • 重構更牢靠
  • 減小沒必要要的判斷

Flow JS類型檢查器

2014 facebook 類型註解可控不是都必須加npm

  • flow安裝編程

    npm install flow-bin -D
    npx flow init  //生成.flowconfig

    使用flow時關閉vscode的語法校驗,由於添加的類型註解不是標準的js語法數組

    文件 -> 首選項 -> 設置 -> javascript validate

    添加註釋@flow,標記進行flow檢查的文件瀏覽器

控制檯使用 yarn flow 會查找node_modules裏的.bin/flow進行類型檢查

//@flow

function sum(n:number,m:number){
  return n+m
}

// console.log(sum("100",100)) //"100"會報錯
console.log(sum(100,200))

yarn flow stop 結束服務

Flow 移除註解

@flow並非js的語法。所以執行 node +文件.js 或瀏覽器中 會在控制檯報錯

編碼事後自動移除掉類型註解

  • 方式1 flow官方移除

    • 安裝:yarn add flow-remove-types --dev
    • 使用:yarn flow-remove-types . -d dist 點(改爲src)是全部文件 後面是輸出位置,做用是去除類型註解,在node和瀏覽器中使用
    • 會在dist生成對應js文件
  • 方式2 babel插件

    • 安裝:

      npm i @babel/core @babel/cli @babel/preset-flow -D

      yarn add @babel/core @babel/cli @babel/preset-flow --save

    • 使用:yarn babel src/part2_typescript/ts_typescript_06.js -d dist/js
    • yarn babel src -d dist 編譯src文件用babelflow

Flow vscode插件

  • Flow Language Support,好處是在編譯階段就報錯上面都是運行後控制檯報錯

Flow 類型推斷

  • 建議仍是添加類型註解

    function square(n){
    return n * n
    } 
    // square("100") //n報錯
    
    let num:number = 1
    // num = "streing"

    Flow類型註解類型

  • string number boolean null undefined symbol
  • array object function
const a:string = "1"
const b:number = NaN//100, Infinity
const c:boolean = true
const d:null = null
const e:void = undefined
const f:symbol = Symbol()
const arr:Array<any> = [1,true]
const arr1:any[] = [1,true]
const fw:[string,number] = ['foow',1] //固定長度類型的數組成爲元組
const obj_:{foo?:string,bar:number} = {foo:"1as",bar:1} //能夠可選

const obj:{[string]:string} = {} //經過key給空對象添加,約定key和value
ob.key1 = "value"

function fn(callback:(string,number)=>void){ //函數參數指定函數
  callback("str",1)
}
fn(function(str,n){
})

特殊類型

//字面量 
const wc:"foo" = "foo"
//字面量配合聯合類型
const type:'success' | "warning" | "danger" = "success"
const nb: string | number = 1
//類型別名
type StringOrNumber = string | number
const sb:StringOrNumber = "stri"
//MayBe類型,在具體類型基礎上擴展了null和undefined兩個值,添加?

const gender:?number = null
const gender1:number | null | void = undefined //同上

//Mixed Any 任意類型 全部類型的聯合類型 any是弱類型,mixed是強類型
//string | number | boolean

function passMix(value:mixed){
  // value * value  報錯
  // value.split(",") 報錯

  if(typeof value === 'string'){ //這個聯合類型須要判斷
    value.split(",")
  }
  if(typeof value === 'number'){
    value * value
  }
}


function passAny(value:any){
  value * value
  value.split(",")
}

typescript

ts官網

  • 安裝

    npm i typscript -D
    npm i ts-node -D
    tsc --init

    tsc xxx

    ts-node xxx

相比較flow 生態健全強大,完善 且漸進式的,什麼不會也徹底看成js用

缺點是多了不少概念,接口泛型枚舉

不一樣文件同名衝突的問題。js不會報錯會覆蓋,可是ts會在顯示階段就提醒你報錯,
所以,經過IIFE或者 export{}形式將文件造成私有做用域

//單獨做用域
// (function(){

  const hello = (name:string) =>console.log(`Hello,${name}`);
  hello("TypeScript")
  //原始類型 

  //string,number,boolean均可以設置成null or undefined
  const a:string = "aa"
  const b:number=1//NaN  Infinity
  const c:boolean= false
  const d:string = null

  const e:void = undefined //null
  const f:null = null
  const g:undefined = undefined
  const h:symbol = Symbol()  

//})()


//改爲模塊,全部成員都是局部成員,不是導出了個對象
export {}

首選項 typescript local -> zh-CN修改爲中文錯誤提示

object類型

//Object類型不單指對象,而是原始類型之外的其餘類型,

//`number,string,boolean,symbol,null或undefined`以外的類型

const foo:object = function (){}//{},[]
const obj:{foo:number,bar:string} = {foo:123,bar:"as"}//這種形式能夠用interface搞定
declare function create(o: object | null): void;

create({ prop: 0 }); // OK
create(null); // OK

create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error

array類型

const arr:Array<number> = [1,2,3]
const arr2:number[] = [1,2,3]

function sum(...args:number[]){
  return args.reduce((executor,current)=>{
    return executor+current
  })
}
console.log(sum(1,2,3))

元組

//明確元素數量和元素類型的數組
const tuple:[number,string] = [1,"1"]
tuple[0]  
const [age,name] = tuple

枚舉

const status = {
  Before:0,
  Doing:1,
  After:2
}

//默認從0開始累加,枚舉會影響咱們編譯後的結果(看下編譯的js文件), 
enum Status{
  Before,
  Doing,
  After
  // After = "aff" //字符串枚舉,不常見
}

// const enum Status{ //加const爲常量枚舉
//   Before,
//   Doing,
//   After
// }

const s = {
  current:Status.Doing
}
console.log(s);

//有const 不能經過索引訪問枚舉名
console.log(Status[0])

函數類型

//函數類型
function sth(a:number,b?:number,c:number=10):string {
  return ""
}
function sth1(a:number,...args:number[]):string {
  return ""
}

const sth2:(a:number,b:number)=>string = function (a:number,b:number):string {
  return ""
}

任意類型

//any不會作類型檢查,語法上不會報錯
function sth3(s:any){

}

隱式類型推斷

//(建議添加明確類型)
let num = 18
// num = "" //類型錯誤
let fx   //any類型

類型斷言

//並非類型轉換,代碼編譯事後不存在了就
const nums = 1;
const mn = nums as number
const mn2 = <number>nums  //jsx 不支持

接口 interface

約定一個對象有哪些成員,這些成員類型是什麼

接口就是用來約束對象的結構,一個對象實現一個接口他就必須擁有接口所約束的成員

接口只是類型約束,運行階段就沒了

interface Person{
  age:number //逗號,分號,不加
  name:string
  sex?:string
  readonly height:number
  [key:string]:any
}

function student(s:Person) {
  console.log(s.age);
  console.log(s.name);
}

const stud:Person = {
  age:1,
  name:"as",
  height:199
}
// stud.height = 180

stud.va = "asd"
stud.as = 112

函數類型接口

interface SearchFunc {
  (source: string, subString: string): boolean;
}
let mySearch = <SearchFunc>function(source: string, subString: string) {
  let result = source.search(subString);
  return result > -1;
}

類類型接口

interface ClockInterface {
    currentTime: Date;
    setTime(d: Date);
}

class Clock implements ClockInterface {
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }
}

類靜態部分與實例部分的區別

當你操做類和接口的時候,你要知道類是具備兩個類型的:靜態部分的類型和實例的類型。 你會注意到,當你用構造器簽名去定義一個接口並試圖定義一個類去實現這個接口時會獲得一個錯誤:

interface ClockConstructor {
    new (hour: number, minute: number);
}

class Clock implements ClockConstructor {
    currentTime: Date;
    constructor(h: number, m: number) { }
}

這裏由於當一個類實現了一個接口時,只對其實例部分進行類型檢查。 constructor存在於類的靜態部分,因此不在檢查的範圍內

所以,咱們應該直接操做類的靜態部分。 看下面的例子,咱們定義了兩個接口, ClockConstructor爲構造函數所用和ClockInterface爲實例方法所用。 爲了方便咱們定義一個構造函數 createClock,它用傳入的類型建立實例。

interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
    tick();
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("beep beep");
    }
}

let digital = createClock(DigitalClock, 12, 17);

接口繼承

interface Shape {
    color: string;
}

interface PenStroke {
    penWidth: number;
}

interface Square extends Shape, PenStroke {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

class類

描述一類具體事務的抽象特徵 (手機)

聲明,修飾符,構造函數,靜態方法

class Person{
  name:string //要聲明相比js(es7)
  private age:number //默認public
  protected gender:boolean
  readonly sex:string = "as" //只讀

  constructor(name:string,age:number){
    this.name = name
    this.age = age
  }
  say(msg:string):void{
    console.log(`hi ${this.name},${msg}`);
  }
}
const mc = new Person("mcgee",18)
mc.name
// mc.age
// mc.gender
class Student extends Person{
  constructor(name:string,age:number){
    super(name,age)
    console.log(this.gender); //可訪問
    
  }
}
class Student2 extends Person{
  private constructor(name:string,age:number){ //構造函數添加private  則沒法實例化,沒法被繼承
    super(name,age)
    console.log(this.gender);
  }
  static create(name:string,age:number){
    return new Student2(name,age)
  }
}

// new Student2("MC",16) //錯
Student2.create("MC",16) //能夠

//給構造函數添加protected 沒法被實例化,可是能夠被繼承

類與接口

類與類之間有公共特徵,經過接口抽象 (手機和座機都能打電話)
interface Eat{
  eat (food:string):void
}

interface Run{
  run (distance:number):void
}


class Person implements Eat,Run{ //類實現了接口必須有接口的成員
  eat(food:string){

  }
  run(distance:number){

  }
}

// class Animal implements EatAndRun{
//   eat(food:string){

//   }
//   run(distance:number){

//   }
// }

抽象類

相似於接口,約束子類中必須有某個成員,區別是抽象類能夠包含一些具體的實現,接口只能是成員的抽象不包含具體實現

抽象類只能被繼承,不能new

abstract class Animal{
  eat(food:string):void{
    console.log(food);
  }

  abstract run(distance:number):void //抽象方法不須要方法體
}

class Dog extends Animal{
  run(distance:number):void{

  }
}

const d = new Dog()
d.eat("sss")
d.run(100)

泛型

定義函數,接口或類的時候沒有指定具體類型,等到咱們使用的時候再去指定具體類型

目的是極大程度的複用代碼

function  arraynumber(length:number,value:number) :number[]{
  return Array<number>(length).fill(value)
}

const res = arraynumber(3,100) //[100,100,100]

//若是再定一個arraystring
function  arraystring(length:number,value:string) :string[]{
  return Array<string>(length).fill(value)
}

//把定義時不能明確的類型變成參數,使用時傳遞
function createArray<T>(length:number,value:T):T[]{
  return Array<T>(length).fill(value)
}

createArray<string>(4,"mcgee")

泛型類型

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <U>(arg: U) => U = identity;
//泛型類型接口
interface GenericIdentityFn {
    <T>(arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn = identity;
//綁定了接口泛型類型
interface GenericIdentityFn<T> {
    (arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;

泛型類

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

泛型約束

//泛型T知足接口length屬性
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

類型聲明

引入第三方模塊時候,若是第三方模塊不包含類型聲明,能夠自聲明

引入 query-string

import {camelCase} from 'lodash' //@types/lodash
import qs from 'query-string'

declare function camelCase (input:string):string //添加後res:string

const res = camelCase('hello camelCase') //res:any

qs.parse("?key=asdasdq122") //自帶類型約束
相關文章
相關標籤/搜索