共计 9889 个字符,预计需要花费 25 分钟才能阅读完成。
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
// 运行编译后的.js
node hello.js
3. 可应用 ts-node,一次性实现 ts 的编译与运行
// 装置 ts-node
npm install -g ts-node
// 运行 ts
ts-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)=>number
f = 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)
}
// 编译失去的 js
function 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>
}