TS学习应用
一、ts环境搭建
1.ts简介
typescript 是 javascript 的一个超集,在js的根底上,增加了变量类型的限度
2.环境
1.装置node:https://nodejs.org/dist/v16.1...
2.应用包管理器装置ts编译器typescript
npm install -g typescript
编译运行:
// tsc =====> typescript compiler// 编译 将指定ts编译编译成.js,tsc hell.ts -w可实现文件批改后的主动从新编译tsc hello.ts// 运行编译后的.jsnode hello.js
3.可应用ts-node,一次性实现ts的编译与运行
// 装置ts-nodenpm install -g ts-node// 运行tsts-node hello.ts
4.应用webpack搭建hmr环境,实时的看到ts编译运行成果。
二、ts的根本类型
1.类型申明的根本应用形式:
let a: number;let b: string = "hello";function fn(x:number, y:string):void{ console.log(x, y);}let sym:symbol = Symbol("symbol");
2.罕用类型
number、string、boolean类型:
let a:string;let b:boolean;function fu():number{ return 1;}let nu:null = null;let und:undefined = undefined;
字面量类型:
// 间接应用字面量进行类型申明,应用时相当于常量// 能够应用 | 来连贯多个类型let sex: "male" | "female";sex = 'male';// 字面量推断type MethodType = "get" | "post" | "put" | "delete" | "patch";let get: string = "get";function request(method: MethodType): void {}request(get as MethodType);
any类型:
//任意类型,等同于没有类型限度了let d: any; // 显示any类型let m; // 隐式any类型
unknown类型:
let s: string;// unknown 实际上就是类型平安的any// unknown 类型的变量,不能间接赋值给其它类型的变量let e: unknown = "hello";// 将unknown赋值给其它类型// 办法一:类型判断if(typeof e === "string"){ s = e;}// 办法二:类型断言// s = (<string>e);s = e as string;
void与never:
// void 返回值为空值function fn():void{ return undefined||null;}// never 不会有返回值,罕用于用来报错的函数function fn2():never{ throw new Error('error');}
object类型:
// 对象申明一:let a: object; // 能够是任何类型的对象,个别不实用// 对象申明二:let b: { //对象类型申明,蕴含属性限度 name: string, age? : number // ? 示意改属性可选};b = { name: 'jiangjiangwa', age: 18}// 对象申明三:let c:{ name: string, // 任意的字符串属性名,任意类型的any属性值 [x: string]: any}
函数构造类型申明:
// (形参:类型,形参:类型)=>返回值类型let f :(arg1:number,arg2:number)=>numberf = function(n1,n2):number{ return n1+n2;}
array类型:
// 示意数字数组let a:number[];let b:Array<number>;const names: string[] = ["John", "Jane", "Mary"];names.forEach((item)=>{ // 这里的item能够不增加类型注解 console.log(item);})
tuple固定长度的数组:
let h:[number,string];h = [123, "world"];// 应用示列function useState<T>(state: T) { let currentState = state; const changeState = (newState: T) => { currentState = newState; }; const tuple: [T, (newState: T) => void] = [currentState, changeState]; return tuple;}const [counter,setCounter] = useState(0);
enum枚举类型:
enum Gender { Male, Female,}console.log(Gender)let i: { name: string; gender: Gender };i = { name: "孙悟空", gender: Gender.Male, // 'male'};
联结类型:
let a:number|string;a = 1;let b : {name:string}&{age:number};b = { name:'jiangjiangwa', age:18}type IdType = string | number;function printId(id: IdType) { // 外部须要对联结类型做操作时,须要应用typeof 先做类型判断 // narrow type (放大范畴) if(typeof id === 'string') { console.log(id.toUpperCase()); }else{ console.log(id); }}printId('abs');
穿插类型
type MyType = number & string; // 等同于 never 类型interface Colorful { color: string;}interface IRun { running: () => void;}type NewType = Colorful & IRun;const obj: NewType = { color: "red", running() {},};
类型的别名
type myType = string | number;let k:myType = 'hello';
类型断言
const imgEle = document.getElementById("img_show") as HTMLImageElement;imgEle.src = './img/1.jpg';class Person{};class Student extends Person{ studying(){ console.log('studying'); }}function sayHello(person: Person){ (person as Student).studying();}sayHello(new Student());
非空断言
function printMessage(message?:string){console.log(message!.length)
}
可选链
是ES11(ES2020)中减少的个性,它的作用是当对象的属性不存在时,会短路,间接返回undefined,如果存在,那么才会继续执行
function printMessage(message?:string){ console.log(message?.length)}// 编译失去的jsfunction printMessage(message) { console.log(message === null || message === void 0 ? void 0 : message.length);}
??操作符
空值合并操作符(??)是一个逻辑操作符,当操作符的左侧是 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数,与||应用的区别,??值判断null、undefined,而||会判断所有假值,蕴含0、""、false、null、undefined
let message: string |null = "Hello World";const content = message ?? '你好哇,李银河';// const content = message || '你好哇,李银河'; console.log(content);
三、ts编译选项
初始化ts编译配置文件tsconfig.json
tsc --init 应用tsconfig.json后,可批量编译整个我的项目的所有ts文件// tsc 间接编译所有ts文件// tsc -w 编译所有ts文件并监督所有ts文件
tsconfig.json配置参数阐明:
{ /* tsconfig.json 是ts编译器的配置文件,ts编译器会读取该文件,并且依据该文件的配置来编译ts文件。 "include": 用来指定那些ts文件须要被编译 门路:** 递归匹配任意子目录 * 示意任意文件 ? 匹配一个任意字符(不包含目录分隔符 */ "include": ["./src/**/*.ts", "./src/**/*.js", "./main.ts"], // "exclude": ["./node_modules"], //有默认值 "compilerOptions": { //target 用来指定ts被编译为的ES的版本 "target": "ESNext", //ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext "module": "es2015", //指定编译为模块化标准 //lib 用来指定哪些库是须要被蕴含在编译后的js中 能够指定多个 // "lib": ["dom","es6"] // 默认不变 "outDir": "./dist", //指定编译后的js文件输入目录 // 设置outFile后,所有全局作用域中的代码,回合并到对立的js文件中,个别应用打包工具实现 // "outFile": "./dist/bindle.js", // 是否对js文件进行编译,默认是false "allowJs": true, // 是否查看js代码的语法,默认是false,须要在tsconfig.json中设置"allowJs": true "checkJs": true, "removeComments": false, //是否移除正文,默认是false // 不生成编译后的js文件,默认是false.但只须要对ts进行语法查看时,应用 "noEmit": false, // 所有严格查看的总开关 "strict":true, // 产生谬误时,不生成编译文件,默认是false "noEmitOnError": true, "alwaysStrict": true, //是否开启严格模式,默认是false,当应用了模块化语法时,默认开启了严格模式 // 不容许应用隐式any类型,默认是false "noImplicitAny": true, // 不容许不明确类型的this "noImplicitThis": true, "strictNullChecks": false, //是否开启严格空值查看,默认是false } }
四、面向对象
1.类的应用
// 应用class关键字定义一个类/* 对类的属性(实例属性、动态属性)和办法进行形容在对类的静态方法或实列属性进行赋值时,须要被限度 */class Person { // 动态属性 static readonly county: string = "中国"; // 实例属性 name: string = "default"; age = 18; constructor(name: string, age: number) { this.name = name; this.age = age; } // 实列办法 // say: (a: number, b: number) => void = function (a, b) { // console.log(a + b); // }; say(a: number, b: number): number { return a + b; }}const person = new Person("John", 30);
类做类型:
class Person { name:string = '123' eating(){}}// 须要跟类的实例,具备雷同的构造与类型const p1:Person = { name:'jiang', eating(){}}function printPerson(p:Person){ console.log(p.name);}printPerson({ name:'jiang', eating(){}})
extends应用:
凋谢关闭准则(OCP,Open Closed Principle),批改是关闭的, 对扩大凋谢。
class Animal { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } say() { console.log("I am a animal"); } } class Dog extends Animal { constructor(name: string, age: number) { super(name, age); } } class Cat extends Animal { say(): void { console.log('miao miao miao') } // 没有重写contructor办法,创立的实例会调用父类的构造函数 }Cat.prototype.__proto__ = Animal.prototype
抽象类abstract:
(function () { // 不能用来创立实列,专门用来继承的类 // 能够增加形象办法 abstract class Animal { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } // 形象办法,只能定义在抽象类中,子类必须实现该办法 abstract say(): void; } class Dog extends Animal { constructor(name: string, age: number) { super(name, age); } say(): void { console.log('wang wang wang') } } class Cat extends Animal { say(): void { console.log("miao miao miao"); } // 没有重写contructor办法,创立的实例会调用父类的构造函数 }})();
接口interface
const obj: myInterface = { name: "John", age: 30, gender?: "男", say() { console.log("jiang"); }, }; console.log(obj); // 构造用来定义类的构造,也可当作类型申明应用 // 可反复申明(拓展原有接口性能),类型限度叠加,接口中,所有办法,都是形象办法 // 实现接口,就是满足接口的要求 interface myInterface { name: string; age: number; } interface myInterface { gender: string; say(): void; } class Person implements myInterface { name: string; age: number; gender: string; constructor(name: string, age: number, gender: string) { this.name = name; this.age = age; this.gender = gender; } say(): void { throw new Error("Method not implemented."); } } console.log(new Person('jiang',18,'男'));// 接口应用练习interface FrontLanguage { [key: number]: string;}const frontLanguage: FrontLanguage = { 1: "HTML", 2: "CSS", 3: "JavaScript" };interface LengthInterface { 'length': number;}const obj: LengthInterface = { length: 10 };//接口定义函数类型interface CalcFunc { (num1:number,num2:number):number;}const add:CalcFunc = (num1,num2) =>{ return num1 + num2;}
接口的继承
interface Person { name: string; eating: () => void;}interface Animal { runing: () => void;}interface Student extends Person, Animal { sno: number;}
字面量赋值freshness擦除操作:
interface IPerson { name: string; eating: () => void;}const obj = { name: "John", eating: () => {}, age: 18,};// 间接将字面量赋值给变量 会报错// p: IPerson = {// name: "John",// eating: () => {},// age: 18,// }const p: IPerson = obj;console.log(p);
属性封装:
(function () { class Person { private _name: string; get name(): string { return this._name; } set name(value: string) { if (this.name.startsWith("张")) { this._name = value; } else { this._name = "张" + value; } } age: number; constructor(name: string, age: number) { this._name = name; this.age = age; } } let p = new Person("John", 30); console.log(p); p.name = "Tom"; p.age = 10; console.log(p);})();
class+属性封装的简写:
class Dog { constructor(public name: string, private age: number) {} // 等同于 // public name: string; // private age: number; // constructor(name: string, age: number) { // this.name = name; // this.age = age; // } }
泛型:
形式一:通过 <类型> 的形式将类型传递给函数;
形式二:通过类型推到,主动推到出咱们传入变量的类型:
function foo<T>(arg:T):T { // 这里时,会将arg类型推导进去,赋值给T return arg;}foo<string>('123');foo(123);/* 在定义函数或是类是,如果遇到类型不明确就能够应用泛型 定义了一个示意类型的变量 */interface Inter { length: number;}/* 泛型限度,须要合乎接口类型限度T extends Inter 示意泛型T必须是Inter实现类(子类) */function fn2<T extends Inter>(a: T): number { return a.length;}fn2("1");// 泛型接口interface IFoo<T> { initValue: T; valueList: T[]; getValue(): T;}class Foo implements IFoo<number> { initValue: number = 0; valueList: number[] = [1, 3, 4, 5]; getValue(): number { return this.initValue; }}// 泛型类class Point<T> { x: T; y: T; constructor(x: T, y: T) { this.x = x; this.y = y; }}let point: Point<number> = new Point<number>(1, 2);
罕用泛型名称:
T:Type的缩写,类型
K、V:key和value的缩写,键值对
E:Elment的缩写,元素
O:Object的缩写,对象
五、模块化
命名空间在TypeScript晚期时,称之为外部模块,次要目标是将一个模块外部再进行作用域的划分,避免一些命名抵触的问题。
export namespace time { // 这里时模块的导出 在别的模块应用 export function format(time: string) { // 这里是命令空间的导出,模块内应用 return "3033-01-01T" + time + ":00.000Z"; } function foo(){ }}export namespace price { export function format(price: number) { return price.toFixed(2); }}time.format('2-2')// time.foo() // error: foo is not exported,没有在明明空间导出的,只能在命名空间外部应用
六、类型申明
另外的一种typescript文件:.d.ts文件
p 咱们之前编写的typescript文件都是 .ts 文件,这些文件最终会输入 .js 文件,也是咱们通常编写代码的中央;
p 还有另外一种文件 .d.ts 文件,它是用来做类型的申明(declare)。 它仅仅用来做类型检测,告知typescript咱们有哪些类型;
1.内置类型申明
内置类型申明是typescript自带的、帮忙咱们内置了JavaScript运行时的一些标准化API的申明文件;
p包含比方Math、Date等内置类型,也包含DOM API,比方Window、Document等;
typescript/lib/*.d.ts文件
2.内部定义类型申明
应用一些库(比方第三方库)时,须要的一些类型申明。
这些库通常有两种类型申明形式:
a.本人库中进行类型申明(编写.d.ts文件),比方axios下index.d.ts文件
b形式二:通过社区的一个私有库DefinitelyTyped寄存类型申明文件 p该库的GitHub地址:https://github.com/Definitely...
该库查找申明装置形式的地址:https://www.typescriptlang.or...
比方咱们装置react的类型申明: npm i @types/react --save-dev
3.自定义类型申明
自定义lodash库的申明
// index.ts 中import _ from 'lodash';console.log(_.join(['99, 2,','fjk']));types-> _lodash.d.ts文件中declare module 'lodash' { export function join(arr:any[])}// 申明其它类型// 申明函数、类、接口、类型、对象、变量等declare function add(a:number,b:number):number;declare class Person { name:string; age:number; constructor(name:string,age:number);}declare interface IPerson { name:string; age:number;}declare let p:IPerson;// 申明文件declare module '*.jpg' declare module '*.png'declare module '*.vue' {}// 申明命名空间,当间接应用cdn的形式导入时,能够应用declare namespace ${ export function ajax(url:string,options:any):Promise<any>}