各種各樣的類型
基礎類型: number string null undefined symbol boolean void空
對象類型: {} Class function []
const teacher: {
name: string;
age: number;
} = {
name: "Dell",
age: 18
};
const numbers: number[] = [1, 2, 3];
class Person {}
const my: Person = new Person();
const getNumber: () => number = () => {
return 123;
};
枚舉類: 對應的值默認從0開始 可以手動賦值
enum Status {
OFFLINE,
ONLINE,
DELETED
}
console.log(Status.OFFLINE);
console.log(Status[0]);
function getResult(status) {
if (status === Status.OFFLINE) {
return "offline";
} else if (status === Status.ONLINE) {
return "online";
} else if (status === Status.DELETED) {
return "deleted";
} else {
return "error";
}
}
let result = getResult(Status.OFFLINE);
console.log(result);
never: 永遠不會執行完函數
function errorEmitter(): never {
throw new Error();
}
function whileEmitter(): never {
while (true) {}
}
數組:
const numberArr: number[] = [1, 2, 3];
const arr: (number | string)[] = [1, "2", "3"];
const objectArr: { name: string }[] = [{ name: "1" }, { name: "2" }];
元組:
const teacherInfo: [string, string, number] = ["yh", "nv", 10];
const teacherList: [string, number][] = [
["yh", 10],
["hy", 20]
];
type alias 類型別名:
type User = { name: string; age: number };
const objArr: User[] = [
{ name: "1", age: 10 },
{ name: "2", age: 11 }
];
class Teacher {
name: string;
age: number;
}
const objArr1: Teacher[] = [
new Teacher(),
{
name: "h",
age: 10
}
];
type annotation 類型註解 我們來告訴ts變量類型
type inference 類型推斷 ts自動嘗試分析變量類型
接口、類、繼承
接口:
interface Person {
//readonly name: string; //修飾符只讀不能賦值
name: string;
age?: number; //加一個?表示可有可無
[propName: string]: any; //可以傳 名字爲字符串 值爲任何類型
//say(): string;
}
const getName = (person: Person) => {
console.log(person.name);
};
getName({ name: "yh" });
class Users implements Person {
//在類裏用接口
name = "yh";
// say() {
// return "hello";
// }
}
interface Study extends Person {
//接口繼承
// hight: string;
}
類繼承:
class Persons {
name: string = "yh";
getName() {
return this.name;
}
}
//類繼承 Teachers是子類 Persons是父類
class Teachers extends Persons {
getTeacherName() {
return "teacher";
}
getName() {
//super.getName(); 調用父類方法
return super.getName() + "覆蓋父類getName方法";
}
}
const person = new Persons();
console.log(person.getName()); //直接運行ts代碼 ts-node type2.ts
const teacher = new Teachers();
console.log(teacher.getName());
訪問類型: private允許在類內調用 protected允許在類內及繼承的子類中使用 public允許在類的內外調用
public name: string;
//private name: string;
//protected name:string;
sayHi() {
console.log("111");
}
}
類構造器: constructor
class Person3 {
// public name: string;
// constructor(name: string) {
// this.name = name;
// }
constructor(public name: string) {}
}
const person3 = new Person3("yh");
console.log(person3.name);
class Teacher3 extends Person3 {
constructor(age: number) {
super("yh"); //子類用構造器需調用父類構造器
}
}
const teacher3 = new Teacher3(28);
get set:
class Person4 {
constructor(private _name: string) {}
get name() {
return this._name;
}
set name(name: string) {
this._name = name;
}
}
const person4 = new Person4("yh");
console.log(person4.name);
person4.name = "yh"; //賦值
構建一個單例:
class Demo {
private static instance: Demo;
private constructor() {}
static getInstance() {
if (!this.instance) {
this.instance = new Demo();
}
return this.instance;
}
}
const demo1 = Demo.getInstance();
抽象類: 抽象方法 把公用的東西抽象出來
abstract class Geom {
width: number;
getType() {
return "Geom";
}
abstract getArea(): number;
}
class Circle extends Geom {
getArea() {
return 123;
}
}
class Square extends Geom {
getArea() {
return 456;
}
}
抽象接口:
interface Person6 {
name: string;
}
interface teacher6 extends Person6 {}
interface stydent extends Person6 {
age: number;
}
const teacher6 = {
name: "yh"
};
const stydent = {
name: "hy",
age: 18
};
const getUserInfo = (user: Person6) => {
console.log(user.name);
};
getUserInfo(stydent);
聯合類型+類型保護
聯合類型:
interface Bird {
fly: boolean;
sing: () => {};
}
interface Dog {
fly: boolean;
bark: () => {};
}
類型保護:
//類型斷言方式 as語法
function canDo(animal: Bird | Dog) {
if (animal.fly) {
(animal as Bird).sing();
} else {
(animal as Dog).bark();
}
}
//in 語法
function cantDo(animal: Bird | Dog) {
if ("sing" in animal) {
animal.sing();
} else {
animal.bark();
}
}
//typeof 語法
function add(first: string | number, second: string | number) {
if (typeof first === "string" || typeof second === "string") {
return `${first}${second}`;
}
return first + second;
}
//instanceof 語法 不能用interface
class NumberObj {
count: number;
}
function addSecond(first: object | NumberObj, second: object | NumberObj) {
if (first instanceof NumberObj && second instanceof NumberObj) {
return first.count + second.count;
} else {
return 0;
}
}
泛型
泛型是指—–generic 泛指的類型 調用時指定類型
function join<T>(first: T, second: T): T {
return first;
}
join<string>("1", "123");
數組泛型 T[]
function map<T>(params: Array<T>) {
return params;
}
map<string>(["123"]);
多個泛型
function add<T, P>(first: T, second: P) {
return `${first}+${second}`;
}
add<number, string>(1, "11");
類中泛型
class DataManager<T> {
constructor(private data: T[]) {}
getItem(index: number): T {
return this.data[index];
}
}
const data = new DataManager<number>([1, 2]);
data.getItem(0);
泛型繼承
interface Item {
name: string;
}
class DataManager1<T extends Item> {
constructor(private data: T[]) {}
getItem(index: number): string {
return this.data[index].name;
}
}
const data1 = new DataManager1([{ name: "dd" }]);
使用泛型作爲一個具體的類型註解
const funcs: <T>() => string = <T>() => {
return "123";
};
function hello<T>(param: T) {
return param;
}
const func: <T>(param: T) => T = hello;
泛型中使用keyof語法
interface Person {
name: string;
age: number;
}
class Teacher {
constructor(private info: Person) {}
//循環Person -> T的類型爲string ->返回類型爲T的類型
getInfo<T extends keyof Person>(key: T): Person[T] {
return this.info[key];
}
}
const teacher = new Teacher({
name: "dell",
age: 18
});
const test = teacher.getInfo("name");
console.log(test);
namespace命名空間
在ts中初步的模塊化思想就是namespace(命名空間)
//編譯後只生成一個變量
namespace Home {
class Header {
constructor() {
const elem = document.createElement("div");
elem.innerText = "Header";
document.body.appendChild(elem);
}
}
class Content {
constructor() {
const elem = document.createElement("div");
elem.innerText = "Content";
document.body.appendChild(elem);
}
}
//只暴露這一個類
export class Page {
constructor() {
new Header();
new Content();
}
}
//定義接口
export interface Uset{
name:string
}
//定義子空間
export namespace childHome Uset{
export class Test{}
}
}
兩個ts文件中命名空間相互引用時,會使用依賴聲明來標註
聲明方式:///<reference path=’./components.ts’/>
.d.ts註解文件
ts裏有一種獨特的文件,以.d.ts結尾,這種文件叫做類型描述文件。註解文件通常使用declare關鍵字描述類型
這裏以jquery爲例,現在想在ts文件種使用jq的方法,如下:
//import $ from "jquery"; //es6引入jq模塊包 這裏的引用名字和註解文件裏的名字要相同
$(function() {
$("body").html("123");
new $.fn.init();
});
這時需要創建一個jquery.d.ts文件幫助ts理解jq,分爲兩種情況,外部引入jq和Es6引入jq模塊包
第一種 (外部引入jq.js文件)
函數重載:聲明 -> $的類型是函數,接收函數,返回值是空
interface JqueryInstance {
html: (html: string) => {};
}
declare function $(readyFunc: () => void): void;
declare function $(selector: string): JqueryInstance;
//對類和對象進行類型定義,命名空間嵌套
declare namespace $ {
namespace fn {
class init {}
}
}
interface的方式實現函數重載
interface JQuery {
(readyFunc: () => void): void;
(selector: string): JqueryInstance;
}
declare var $: JQuery;
第二種(Es6引入jq模塊包)
Es6模塊化必須要添加註解 module後的名字和引用的名字一樣
declare module "jquery" {
interface JqueryInstance {
html: (html: string) => {};
}
//混合類型
function $(readyFunc: () => void): void;
function $(selector: string): JqueryInstance;
namespace $ {
namespace fn {
class init {}
}
}
export = $;
}
奇奇怪怪的裝飾器
學習準備:裝飾器是實驗性特性,未來可能會不是這種用法
現在想要使用需要在tsconfig.json文件中打開這兩個註釋,否則使用裝飾器會報錯
裝飾器本身是一個函數 通過@符號使用
類的裝飾器
接收的參數是類的構造函數 創建類後立即執行
多個裝飾器執行時 從下到上執行
function testDecorator(constructor: any) {
//在類上創建getName方法
constructor.prototype.getName = () => {
console.log("dell");
};
}
function testDecorator1(constructor: any) {
console.log("先執行");
}
//多個裝飾器執行時 從下到上執行
@testDecorator
@testDecorator1
class Test {}
const test = new Test();
(test as any).getName();
//對裝飾器進行 工廠函數包裝
function testDecorator2(flag: boolean) {
if (flag) {
return function(constructor: any) {
constructor.prototype.getName = () => {
console.log("dell");
};
};
} else {
return function(constructor: any) {};
}
}
@testDecorator2(true)
class Test2 {}
const test2 = new Test2();
//(test2 as any).getName();
//new (...args: any[])=> {} 這是一個構造函數 接收很多都是any類型的參數 返回很多any類型的值
function testDecorator3<T extends new (...args: any[]) => {}>(constructor: T) {
//對類裏的構造函數做擴展 會先執行原來的構造函數
return class extends constructor {
name = "lee";
getName() {
return this.name;
}
};
}
@testDecorator3
class Test3 {
name: string;
constructor(name: string) {
this.name = name;
}
}
const test3 = new Test3("dell");
//工廠模式 ->識別裝飾器中新增的類方法
function testDecorator4() {
return function<T extends new (...args: any[]) => {}>(constructor: T) {
//對類裏的構造函數做擴展 會先執行原來的構造函數
return class extends constructor {
name = "lee";
getName() {
return this.name;
}
};
};
}
const Test4 = testDecorator4()(
class {
name: string;
constructor(name: string) {
this.name = name;
}
}
);
const test4 = new Test4("dell");
test4.getName();
方法裝飾器
普通方法接收的參數:target對應類的prototype原型,key對應裝飾函數的名字,descriptor設置方法的屬性
靜態方法接收的參數:target對應類的構造函數
function getNameDecorator(
target: any,
key: string,
descriptor: PropertyDescriptor
) {
//此函數是否可以在外部再次修改
descriptor.writable = false;
//對方法的內容做變更
descriptor.value = function() {
return "Decorator";
};
}
class Func {
name: string;
constructor(name: string) {
this.name = name;
}
//普通方法
@getNameDecorator
getName() {
return this.name;
}
//靜態方法
// @getNameDecorator
// static getName1() {
// return 123;
// }
}
const func = new Func("dell");
console.log(func.getName());
訪問器裝飾器
function visitDecorator(
target: any,
key: string,
descriptor: PropertyDescriptor
) {}
class Visit {
private _name: string;
constructor(name: string) {
this._name = name;
}
get name() {
return this._name;
}
@visitDecorator
set name(name: string) {
this._name = name;
}
}
const visit = new Visit("dell");
visit.name = "1233333";
console.log(visit.name);
屬性裝飾器
function nameDecorator(target: any, key: string): any {
//target[key] = 'lee'; //這裏修改的使原型上的屬性,不是實例上的 獲取方法->(names as any).__proto__.name
//創建一個替換name的descriptor,使name不能在外部被修改
const descriptor: PropertyDescriptor = {
writable: false
};
return descriptor;
}
class Name {
@nameDecorator
name = "Dell";
}
const names = new Name();
console.log(names.name);
參數裝飾器
三個參數 target原型 method方法名 paramIndex參數的位置
function paramDecorator(target: any, method: string, paramIndex: number) {}
class Param {
getInfo(name: string, @paramDecorator age: number) {
console.log(name, age);
}
}
const param = new Param();
param.getInfo("dell", 18);
一個裝飾器的小例子
使用裝飾器統一判斷uesrInfo是否是 undefined
const uesrInfo: any = undefined;
function catchErroe(msg: string) {
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const fn = descriptor.value;
descriptor.value = function() {
try {
fn();
} catch (e) {
console.log(`${msg}有問題`);
}
};
};
}
class GetInfo {
@catchErroe("name")
getNAme() {
return uesrInfo.name;
}
@catchErroe("age")
getAge() {
return uesrInfo.age;
}
}
const getInfo = new GetInfo();