天天看點

Ts進階

Ts進階

Ts進階

環境搭建

npm install typescript -g
tsc demo01.ts
node demo01.js
           
npm install ts-node -g
ts-node demo01.ts
           

靜态類型

// 靜态類型
const count: number = 1;
// count = "itxing" // 報錯
console.log(count)

interface XiaoJiejie {
    username: string;
    age: number;
}

const xiaohong: XiaoJiejie = {
    username: "小紅",
    age: 18,
}

console.log(xiaohong)
           

靜态類型:基礎靜态類型和對象類型

number, string, null

,

undefinde

,

symbol

,

boolean

void

對象類型 數組類型 類類型 函數類型

const myCount: number = 0;
const myName: string = "itxing";

const xiaoJiejie: {
    name: string,
    age: number,
} = {
    name: "小姐姐",
    age: 18
}

const xiaoJiejies: string[] = [
    "小姐姐1", "小姐姐2"
]

class Person {}
const person: Person = new Person()

const jianXiaoJiejie: () => string = () => {
    return "美女";
}
           

類型注解和類型推斷

// 類型注解 類型推斷
let a: number; // 類型注解
a = 0;

let countInference = 123; // 類型推斷
           
  • 如果

    TS

    能夠自動分析變量類型, 我們就什麼也不需要做了
  • 如果

    TS

    無法分析變量類型的話, 我們就需要使用類型注解
// 不用寫類型注釋
const one = 1;
const two = 2;
const three = one + two;

// 用寫類型注釋的
function getTotal(one: number, two: number) {
    return one + two;
}
const total = getTotal(1, 2)
           

函數參數和傳回類型的注解

function getTotal(one: number, two: number): number {
    return one + two;
}
const total = getTotal(1, 2);
           

void

function syaHello(): void {
    console.log('hello world')
}
           

never

// never 傳回值類型 永遠執行不完
function errorFunction(): never {
    throw new Error();
    console.log("hello world");
}

function forNever(): never {
    while (true) {}
    console.log("hello world");
}
           

函數參數為對象(解構)時

function add({one, two}): number {
    return one + two;
}

function add({ one, two }: { one: number, two: number }): number {
  return one + two;
}

const total = add({one: 1, two: 2})

// 錯誤寫法
function add({one: number, two: number}): number {
    return one + two;
}
function add({one}: number): number {
    return one + two;
}

// 正确寫法
function add({one, two}: {one: number, two: number}): number {
    return one + two;
}
           

數組類型注解的方法

一般數組類型定義

const numberArr:number[] = [1,2,3];
const string: string[] = ['a','b','c'];
const undefinedArr: undefined[] = [undefined];

const arr:(number | string)[] = [1, 'string', 2];
           

數組中對象類型的定義

const xiaojiejie: {
    name: string,
    age: number
}[] = [
    {name: '劉英', age: 18},
    {name: '謝大腳', age: 20}
]

// 别名 或 類來限制類型
type Lady = {
    name: string,
    age: number
}
class Madon {
    name: string;
    age: number
}
const xiaojiejie: Lady[] = [
    {name: '劉英', age: 18},
    {name: '謝大腳', age: 20}
]
           

元組的使用和類型限制

const xiaojiejie:(string|number)[] = ['dajiao', 'teacher', 28]

//  以下情況也不會報錯,這是有問題的
const xiaojiejie:(string|number)[] = ['dajiao', 18, 'teacher']

元組可以固定每個位置上的元素類型
const xiaojiejie: [string, string, number] = ["dajiao", "teacher", 28];
           

interface 接口

const screenResume = (name: string, age: number, bust: number) => {
  age < 24 && bust >= 90 && console.log(name + "進入面試");
  age > 24 || (bust < 90) && console.log(name + "你被淘汰了")
}

const getResume = (name: string, age: number, bust: number) => {
  console.log(name + "年齡是:" + age);
  console.log(name + "胸圍是:" + bust)
}

screenResume("大腳", 18, 94)
getResume("大腳", 18, 94)
           

接口 interface

interface Girl {
  name: string;
  age: number;
  bust: number;
}

const girl = {
  name: "大腳",
  age: 18,
  bust: 94,
}

const screenResume = (girl: Girl) => {
  girl.age < 24 && girl.bust >= 90 && console.log(girl.name + "進入面試")
  girl.age > 24 && girl.bust < 90 && console.log(girl.name + "你被淘汰")
}

const getResume = (girl: Girl) => {
  console.log(girl.name + "年齡是:" + girl.age);
  console.log(girl.name + "胸圍是:" + girl.bust)
}

screenResume(girl);
getResume(girl);
           

// 接口非必須屬性定義

// 接口非必選值定義
interface Girl {
  name: string;
  age: number;
  bust: number;
  waistline?: number;
}
           

// 允許加入任何值

interface Girl {
  name: string;
  age: number;
  bust: number;
  waistline?: number;
  [propName: string]: any
}
           

接口和類的限制

interface Girl {
    name: string;
    age: number;
    bust: number;
    waistline?: number;
    [propName: string]: any;
    say(): string;
}

const girl = {
    name: 'itxing',
    age: 18,
    bust: 94,
    waistline: 21,
    sex: '女',
    say() {
        return '歡迎光臨 ,天上人間大保健!!'
    },
    teach() {
        return '我是一個老師'
    }
}

const getResume = (girl: Girl) => {
    console.log(girl.name + "年齡是:" + girl.age);
    console.log(girl.name + "胸圍是:" + girl.bust);
    girl.waistlin && console.log(girl.name + "腰圍是:" + girl.waistline);
    girl.sex && console.log(girl.name + "性格是:" + girl.sex)
}
getResume(girl)

class DaMeiZi implements Girl {
    name = '奶茶妹';
    age = 18;
    bust = 90;
    say() {
        return 'hello 奶茶妹'
    };
}
// 如果去掉say方法就會報錯
           

接口繼承

interface Teacher extends Girl {
    teach(): string;
}

const getResume = (girl: Teacher) => {
    console.log(girl.name + "年齡是:" + girl.age);
    console.log(girl.name + "胸圍是:" + girl.bust);
    girl.waistlin && console.log(girl.name + "腰圍是:" + girl.waistline);
    girl.sex && console.log(girl.name + "性格是:" + girl.sex)
}
getResume(girl)
// girl 對象中要追加teach方法
           

類的繼承

class Lady {
    content = 'Hi,帥哥';
    sayHello() {
        return this.content;
    }
}
class XiaoJieJie extends Lady {
    sayLove() {
        return 'I Love You';
    };
    // // 類的重寫
    // sayHello() {
    //     return "Hi , honey!";
    // }
    sayHello() {
        return super.sayHello() + '.你好'
    }
}
const goddess = new XiaoJieJie();
console.log(goddess.sayHello());
console.log(goddess.sayLove())
           

類的重寫

class XiaoJieJie extends Lady {
    sayLove() {
        return 'I Love You';
    };
    // 類的重寫
    sayHello() {
        return "Hi , honey!";
    }
    sayHello() {
        return super.sayHello() + '.你好'
    }
}
           

super關鍵字

用于通路和調用一個對象的父對象上的函數

用法:

super([arguments]); 
// 調用 父對象/父類 的構造函數

super.functionOnParent([arguments]); 
// 調用 父對象/父類 上的方法
           

示例:

class DaMeiZi extends Lady {
    sayLove() {
        return 'I Lover you!'
    }
    sayHello() {
        return super.sayHello() + '.你好'
    }
}

const goddess = new DaMeiZi()
console.log(goddess.sayHello())
           

類的通路類型private protected public

class Person {
    name: string;
}
const person = new Person();
person.name = 'itxing';
console.log('================', person.name);
           

預設對name的通路屬性進行了定義public

public:允許在類的内部和外部被調用

class Person {
    public name: string;
    public sayHello() {
        console.log(this.name + ' say Hello')
    }
}

const person = new Person();
person.name = 'itxing';
person.sayHello();
console.log(person.name);
           

private: 隻允許在類的内部被調用,外部不允許調用

class Person {
    private name: string = 'itxing';
    public sayHello() {
        // 類内部通路
        console.log(this.name + ' say Hello')
    }
}
// 類外部通路報錯
const person = new Person()
person.name = 'itxing';  // 報錯
person.sayHello();  // 輸出 itxing say hello
console.log(person.name);  // 報錯
           

允許在類中及繼承的子類中使用

class Person {
    protected name: string = 'itxing';
    public sayHello() {
        console.log(this.name + ' say Hello')
    }
}
const person = new Person();
person.name = '頁面仔';  // 報錯

class Teacher extends Person {
    public sayBye() {
        console.log(this.name + ' say Bye')
    }
}

const teacher = new Teacher();
teacher.sayBye();  // 正常
           

類的構造函數

希望在new出對象的時候,直接通過傳遞參數的形式

class Person {
    public name: string;
    constructor(name: string) {
        this.name = name;
    }
}
const person = new Person('itxing');
console.log(person.name);

// 簡寫
class Person {
    constructor(public name: string) {}
}
           

類繼承中的構造器寫法

class Person {
    constructor(public name: string) {}
}
class Teacher extends Person {
    constructor(public age: number, name: string) {
        super(name);
    }
}
const teacher = new Teacher(18, 'itxing');
console.log(teacher.age);
console.log(teacher.name);
           

類中可以不寫構造函數(預設執行構造函數),子類繼承父類時有構造函數時必須執行super(),需要傳值進行傳值操作

class Person {}

class Teacher extends Person {
    constructor(public age: number) {
        super()
    }
}
const teacher = new Teacher(20);
teacher.age;
           

類的Getter、Setter

getter屬性的關鍵字:get,擷取某屬性的值,它不是一個方法,歸根到底還是屬性

setter屬性的關鍵字:get,改變某屬性的值

getter

class Person {
    constructor(private _age: number) {}
    get age() {
        return this._age - 10;
    }
}
const person = new Person(28);
console.log(person.age);
           

setter

class Person {
    constructor(private _age: number) {}
    get age() {
        return this._age - 10
    }
    set age(age: number) {
        this._age = age;
    }
}
const person = new Person(28);
console.log(person.age);
person.age = 25;
console.log(person.age);
           

類的static

正常寫法

class Girl {
  sayLove() {
    return "I Love you";
  }
}

const girl = new Girl();
console.log(girl.sayLove());
           

static

class Girl {
    static sayLove() {
        return 'I love you';
    }
}
console.log(Girl.sayLove());
           

類的隻讀屬性

class Person {
    constructor(public name: string) {}
}
const person = new Person('itxing')

console.log(person.name)
           

若name隻能讀,則用readonly

class Person {
    public readonly _name: string;
    constructor(name: string) {
        this._name = name;
    }
}
const person = new Person('itxing');
person._name = '頁面仔';  // 報錯
console.log(person._name)
           

抽象類

BaseTeacher、MiddleTeacher、SeniorTeacher類被抽象類Person限制,必須有skill方法

abstract class Person {
    abstract skill()  // 因為沒有具體方法,是以不寫大括号
}

class BaseTeacher extends Person {
    skill() {
        console.log('普通老師');
    }
}

class MiddleTeacher extends Person {
    skill() {
        console.log('中級老師');
    }
}

class SeniorTeacher extends Person {
    skill() {
        console.log('進階老師');
    }
}
           

聯合類型和類型保護

所謂聯合類型:一個變量可能有兩種或兩種以上的類型

interface BaseTeacher {
  teach: boolean;
  say: () => {};
}

interface MiddleTeacher {
  teach: boolean;
  skill: () => {}
}

function judgeWho(teacher: BaseTeacher | MiddleTeacher) {
  teacher.say();  // 報錯
}
           

類型保護-類型斷言

// 根據teach值,通過斷言方式進行類型保護
function judgeWho(teacher: BaseTeacher | MiddleTeacher) {
  if (teacher.teach) {
    (teacher as MiddleTeacher).skill();
  } else {
    (teacher as BaseTeacher).say();
  }
}
           

類型保護-in文法

function judgeWho(teacher: BaseTeacher | MiddleTeacher) {
  if ('skill' in teacher) {
    teacher.skill();
  } else {
    teacher .say();
  }
}
           

類型保護-typeof文法

function add(first: string | number, second: string | number) {
  if (typeof first === 'string' || typeof second === 'string') {
    return `${first}${second}`
  }
  return first + second;
}
           

類型保護-instanceof文法

function addObj(first: object | NumberObj, second: object | NumberObj) {
  if (first instanceof NumberObj && second instanceof NumberObj) {
    return first.count + second.count;
  }
  return 0;
}
           

Enum枚舉類型

enum Status {
  Base,
  Middle,
  Senior
}
function getLearn(level: any) {
  if (level === Status.Base) {
    return 'base';
  } else if (level === Status.Middle) {
    return 'middle'
  } else if (level === Status.Senior) {
    return 'senior'
  }
}

console.log(getLearn(1))  // 輸出 middle
           

enum預設0 1 2,如果想從1開始

enum Status {
  Base = 1,
  Middle,
  Senior
}
           

泛型

function join(first: string | number, second: string | number) {
  return `${first}${second}`
}
console.log(join(頁面仔', '小楊'))
           

如果希望first和second的資料類型相同,我們就可以使用泛型

function join<T>(first: T, second: T) {
  return `${first}${second}`
}
console.log(join<string>('頁面仔', '小楊'))
           

泛型中數組的使用

function myFun<T>(params: T[]) {
  return params;
}
console.log('============', myFun<string>(['123', '456']))
           

function myFun<T>(params: Array<T>) {
  return params;
}
           

多個泛型的定義

function join<T, P>(first: T, second: P) {
  return `${first}${second}`
}
console.log(join<string, number>('1', 2))
           

泛型類型推斷(不推薦)

console.log(join('1', 2))
           

初始類的泛型

class SelectTeacher<T> {
  constructor(private teachers: T[]) {}
  getTeacher(index: number): T {
    return this.teachers[index];
  }
}
const selectTeacher = new SelectTeacher(['初級老師', '中級老師', '進階老師']);
console.log('==================', selectTeacher.getTeacher(1))
           

泛型中的繼承

interface Teacher {
  name: string;
}
class SelectTeacher<T extends Teacher> {
  constructor(private teachers: T[]) {}
  getTeacher(index: number): string {
    return this.teachers[index].name
  }
}
const selectTeacher = new SelectTeacher([
  { name: '初級老師' },
  { name: '中級老師' },
  { name: '進階老師' }
])
console.log('===============', selectTeacher.getTeacher(1))
           

泛型限制

泛型可以是任意類型,但現在要求泛型是string或number

class SelectTeacher<T extends number | string> {
	// ......
}
           

命名空間Namespace

mkdir ts-web
cd ts-web
npm init -y
tsc -init
mkdir src dist
touch index.html
cd src
touch page.ts
// 配置 tsconfig.json  "outDir": "./dist",  "rootDir": "./src"
           

檢視相關代碼

// page.ts
console.log('hello itxing')
           

index.html中引入page.js

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./dist/page.js"></script>
</head>
<body>te-web</body>
</html>
           

終端執行指令并打開頁面

tsc
           
Ts進階

沒有命名空間的問題

// page.ts
class Header {
  constructor() {
    const elem = document.createElement('div')
    elem.innerText = 'This is Header'
    document.body.appendChild(elem)
  }
}

class Content {
  constructor() {
    const elem = document.createElement('div')
    elem.innerText = 'This is Content'
    document.body.appendChild(elem)
  }
}

class Footer {
  constructor() {
    const elem = document.createElement('div')
    elem.innerText = 'This is Footer'
    document.body.appendChild(elem)
  }
}

class Page {
  constructor() {
    new Header();
    new Content();
    new Footer();
  }
}
           
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./dist/page.js"></script>

</head>
<body>
  te-web
  <script> new Page() </script>
</body>
</html>
           

通過檢視

./build/page.js

檔案可以看出全部都是

var

聲明的變量,過多的全局變量會讓我們代碼變的不可維護。

命名空間的使用

namespace Home {
  class Header {
    constructor() {
      const elem = document.createElement('div')
      elem.innerText = 'This is Header'
      document.body.appendChild(elem)
    }
  }

  class Content {
    constructor() {
      const elem = document.createElement('div')
      elem.innerText = 'This is Content'
      document.body.appendChild(elem)
    }
  }

  class Footer {
    constructor() {
      const elem = document.createElement('div')
      elem.innerText = 'This is Footer'
      document.body.appendChild(elem)
    }
  }
  export class Page {
    constructor() {
      new Header();
      new Content();
      new Footer();
    }
  }
}
           
new Home.Page()
           

命名空間實作元件化

cd src
touch components.ts
           
namespace Components {
  export class Header {
    constructor() {
      const elem = document.createElement('div')
      elem.innerText = 'This is Header'
      document.body.appendChild(elem)
    }
  }

  export class Content {
    constructor() {
      const elem = document.createElement('div')
      elem.innerText = 'This is Content'
      document.body.appendChild(elem)
    }
  }

  export class Footer {
    constructor() {
      const elem = document.createElement('div')
      elem.innerText = 'This is Footer'
      document.body.appendChild(elem)
    }
  }
}
           

page.ts

namespace Home {
  export class Page {
    constructor() {
      new Components.Header();
      new Components.Content();
      new Components.Footer();
    }
  }
}
           

index.html

<script src="./dist/components.js"></script>
<script src="./dist/page.js"></script>
           

多檔案編譯成一個檔案

tsconfig.json

"module": "amd",
"outFile": "./dist/page.js"
           

這樣會編譯成一個檔案,index.html中隻需引入page.js即可

關注公衆号: 頁面仔小楊 【實戰幹貨、原創分享】

繼續閱讀