TypeScript学习篇-类型介绍使用、ts相关面试题

文章目录

  • 基础知识
    • 基础类型: number, string, boolean, object, array, undefined, void(代表该函数没有返回值)
      • unknown
      • enum(枚举): 定义一个可枚举的对象
      • 联合类型: | (联合类型一次只能一种类型;而交叉类型每次都是多个类型的合并类型。)
      • 交叉类型: & (联合类型一次只能一种类型;而交叉类型每次都是多个类型的合并类型。)
      • any 类型
      • null 和 undefined
        • null
        • undefined
      • never类型
      • type
      • interface:接口,可以描述一个对象或函数
    • class 类
    • 函数
    • 泛型: 不定义为具体类型
    • 迭代器和生成器
    • 装饰器
    • 继承、多态、重载、重写
      • 继承
      • 多态
      • 重载
      • 重写
      • Record
      • Paritial
      • Reuqired
      • Readonly
      • Exclude
      • Extract
      • in
  • TypeScript 编译原理
  • 面试题及实战
    • 什么是类型推论,以下代码ts推论出的类型是什么
    • 1. 你觉得使用ts的好处是什么?
    • 2. type 和 interface的异同
      • 2.1 都可以描述一个对象或者函数
      • 2.2 都允许拓展(extends)
      • 2.3 只有type可以做的:声明基本类型别名,联合类型,元组等类型
      • 2.4 interface可以多次定义并被视为合并所有声明成员,type不支持
      • 2.5 type能使用in关键字生成映射类型,interface不行
    • 3. 如何基于一个已有类型, 扩展出一个大部分内容相似, 但是有部分区别的类型?
    • 4. 什么是泛型, 泛型的具体使用?
    • 5. 写一个计算时间的装饰器
    • 6. 写一个缓存的装饰器
    • 7. 实现一个路由跳转 通过ts约束参数的routeHelper
    • 8. 实现一个基于ts和事件模式的countdown基础类
      • 使用
    • 9. npm install一个模块,都发生了什么
    • 10. eventemitter3

执行ts文件命令:

tsc 文件.ts

基础知识

基础类型: number, string, boolean, object, array, undefined, void(代表该函数没有返回值)

类型关键字描述
任意类型any声明为 any 的变量可以赋予任意类型的值。能不用any就不用any。
数字类型number双精度64位浮点值, 它可以用来表示整数和分数:
let num: number = 666;
字符串类型stringlet str: string = '呀哈哈';
布尔类型booleanlet flag: boolean = true;
数组类型声明变量为数组
在元素类型后面加[]: let arr: number[] = [1,2];,
或使用数组泛行: let arr:Array<number> = [1,2];
元组元组类型用来表示已知元素数量和类型的数组, 各元素的类型不必相同, 对应位置的类型需要相同:
let x:[string,number];
正确: x = ['呀哈哈', 2];
错误: x = [2, '呀哈哈'];
枚举enum枚举类型用于定义数值集合
enum Color {Red, Green, Blue};
let c : Color = Color.Blue;
console.log(c); // 2
voidvoid用于标识方法返回值的类型, 表示该方法没有返回值,不返回或返回undefined
function hello(): void{ alert('Hello World'); }。常用于表示函数没有返回值。
nullnull表示对象值缺失
undefinedundefined用于初始化变量为一个未定义的值
nevernevernever是其他类型(包括 null 和 undefined) 的子类型, 代表从不会出现的值.对于函数而已never表示函数用于执行不到返回值哪一步(抛出异常或死循环)的返回值类型。常用于构造条件类型来组合出更灵活的类型定义。
unknownunknown和any类型,但使用前必须进行断言或守卫。声明时如果不确定具体类型则可以使用,在使用时用类型断言或类型守卫进行类型收缩。

unknown

let e : unknown = '123';
if(typeof e == 'string'){e = 111;
}else{e = 123;
}
console.log("🚀 ~ e:", e) // 111
console.log("🚀 ~ e type:", typeof e) // number

enum(枚举): 定义一个可枚举的对象

数字枚举的声明可以分为两大类:带有初始化器和不带初始化器

  • 不带初始化器,枚举成员默认从 0 开始,依次递增
  • 带有初始化器,可以分为两种
    • 使用初始化器并指定初始化的常数,未使用初始化器的成员取值是在上一个成员的基础上+1
    • 使用初始化器并初始化值是对已经声明的枚举的枚举成员的引用
const Enum1 = {'RUN':'run', // 0 'EAT':'eat', // 1
}
enum Enum2 {'RUN',// 默认 RUN = 0'EAT', // 默认 EAT = 1'YHH' = 10,'YHH2', // 11'ABC' = 'abc', // 使用 '=' 复制'YHH3', // 没有这个属性
}
// 使用初始化器并初始化值是对已经声明的枚举的枚举成员的引用
enum Enum3 {one: Enum2.YHH, // 10two, // 11
}
// 使用
const eat = Enum2.EAT;const getValue = () => {return 0
}enum List {A = getValue(),B = 2,  // 此处必须要初始化值,不然编译不通过C
}
console.log(List.A) // 0
console.log(List.B) // 2
console.log(List.C) // 3

联合类型: | (联合类型一次只能一种类型;而交叉类型每次都是多个类型的合并类型。)

交叉类型: & (联合类型一次只能一种类型;而交叉类型每次都是多个类型的合并类型。)

any 类型

任意值是 typescript 针对编程时类型不明确的变量使用的一种数据类型. 常用于以下三种情况

// 变量的值会动态改变时, 比如来着用户的输入, 任意值类型可以让这些变量跳过编译阶段的类型检查
let x: any = 1;
x = 'yhh';
x = false;// 改写现有代码时, 任意值允许在编译时可选择地包含或移除类型检查
let x: any = 4;
x.isEmpty(); // 正确, isEmpty方法在运行时可能存在, 但这里并不会检查
x.toFixed(); // 正确// 定义存储各种类型数据的数组时
ler arrayList: any[] = [1,false,'fine'];
arratList[1] = 100;

null 和 undefined

null

nullJavaScript 中 表示’什么都没有’.

null 是一个只有一个值的特殊类型, 表示一个空对象引用.

typeof 检测 null 返回是 object.

undefined

undefinedjavascript 中是一个没有设置值的变量.

typeof 一个没有值的变量会返回 undefined.

NullUndefined 是其他任何类型(包括void)的子类型. 可以赋值给其他类型, 比如数字类型, 赋值后的类型会变成 nullundefined.

typescript 中启用严格的空检验(--strictnullChecks)特性, 就可以使 nullundefined 只能被赋值给 void 或本身对应的类型.

// 启用 --strictnullChecks 
let x : number;
x = 1;
x = undefined; // 错误, 因为 x 只能是数字类型
x = null; // 错误// 如果一个类型可能出现 null 或 undefined, 可以使用 | 类支持多中类型
// 启用 --strictnullChecks 
let x : number | null | undefined;
x = 1;
x = undefined; // 正确
x = null; // 正确

never类型

never 是其他类型(包括nullundefined)的子类型, 代表从不会出现的值. 这意味着声明never类型的变量只能被never类型所赋值, 在函数中通常表现为抛出异常或无法执行到终止点.

let x : never;
let y : number;x = 123; // 错误, 数字类型不可转为 never 类型// 正确, never 类型可以赋值给 never类型
x = (()=>{ throw new Error('exception') })();
// 正确, never 类型可以赋值给 数字类型
y = (()=>{ throw new Error('exception') })();// 返回值为 never 的函数可以是抛出异常的情况
function error(message:string): never{throw new Error(message);
}
// 返回值为 never 的函数可以是无法被执行到终止点的情况
function loop(): never{while (true){}
}

type

type Action = 'eat'  | 'run';
// 声明 a 变量类型为 Action, 可选值为:'eat', 'run'
const a:Action = 'eat';

interface:接口,可以描述一个对象或函数

interfact object 对象类型

// interface object对象类型
interface User{name: string,age?: number, // 可以定义,可以不定义,非强制的属性// readonly id: number
}// 定义axios.post 返回值类型
axios.post<User>().then();function printUser(user: User): void{console.log("🚀 ~ printUser ~ user.name:", user.name)console.log("🚀 ~ printUser ~ user.age:", user.age)
}
const user1 : User = {name: "张三",age: 18
}
printUser(user1);

interface function 函数类型

interface UserFun{( name: string , age: number ): void;
}
const myFunction: UserFun = (name, age)=>{}

interface array可索引类型

// 可索引类型
interface StringArray {// 定义索引key为number, 索引值为string[index: number]: string;
}
let arr1 : StringArray;
arr1 = ["1","2","3"];
console.log("🚀 ~ arr1:", arr1)let arr2 : StringArray;
arr2 = {1: '呀哈哈', 2: '18'};
console.log("🚀 ~ arr2:", arr2)

class 类

函数

泛型: 不定义为具体类型

// 泛型: 不定义为具体类型
// T: 可以是任意类型,可以理解为占位符,也可以继承接口
function funcT<T>(arg: T): T{return arg;
}
funcT('呀哈哈');
funcT(19);
funcT({name:'呀哈哈'});
funcT({age:18});// 如 以下func1、func2可以统一使用funcT来实现
function func1(arg: string): string{return arg;
}
function func2(arg: number): number{return arg;
}
// T extends User: T必须继承User
function funcTE<T extends User>(arg: T): T{return arg;
}
funcTE({age:18, name: '呀哈哈'});

迭代器和生成器

装饰器

执行顺序:
1、有多个参数装饰器时,从最后一个参数一次向前执行
2、方法和方法参数中参数装饰器先执行
3、类装饰器总是最后执行
4、方法和属性装饰器,谁在前面谁先执行,因为参数属于方法一部分,所以参数会一直紧紧挨着方法执行

类装饰器

function Log(target: any){console.log(target);console.log('in log decorator');
}
@Log
class A{constructor(){console.log('constructor');}
}
new A();

继承、多态、重载、重写

继承

有时候我们定义的泛型不想过于灵活或者说想继承某些类等,可以通过 extends 关键字添加泛型约束。

interface ILengthwise {length: number;
}function loggingIdentity<T extends ILengthwise>(arg: T): T {console.log(arg.length);return arg;
}loggingIdentity(3);
loggingIdentity({length: 10, value: 3});

多态

指允许一个接口表示多种形态,多态允许一个类实例的对象使用相同的方法名,具有不同的表现行为。在TypeScript中,多态通常是通过类的继承和子类重写父类的方法来实现的。

class Animal {makeSound() {console.log("Some generic animal sound");}
}class Dog extends Animal {makeSound() {console.log("Woof!");}
}let animal = new Animal();
let dog = new Dog();animal.makeSound(); // 输出:Some generic animal sound
dog.makeSound();    // 输出:Woof!

重载

指允许一个函数接受不同数量或类型的参数,并执行不同的操作。在TypeScript中,通过为同名函数定义不同的函数签名来实现重载。

// 重载示例
function overload(a: number, b: number): number;
function overload(a: string, b: string): string;
function overload(a: any, b: any): any {if (typeof a === "string" || typeof b === "string") {return a.toString() + b.toString();}return a + b;
}console.log(overload(1, 2)); // 输出:3
console.log(overload("Hello", "World")); // 输出:HelloWorld

重写

指子类重新定义了父类的方法,以改变(重写)其行为。在TypeScript中,子类可以通过使用super关键字来调用父类的方法,并在此基础上添加或修改自己的实现。

class Printer {print(s: string) {console.log('Printer: ' + s);}
}class ColorPrinter extends Printer {print(s: string, color: string) {console.log('ColorPrinter: ' + s + ' in ' + color);}
}let printer = new Printer();
let colorPrinter = new ColorPrinter();printer.print('Hello');        // 输出:Printer: Hello
colorPrinter.print('World', 'blue'); // 输出:ColorPrinter: World in blue

Record

Record<K extends keyof any, T> 的作用是将 K 中所有的属性的值转化为 T 类型。

interface PageInfo {title: string;
}type Page = "home" | "about" | "contact";const x: Record<Page, PageInfo> = {about: { title: "about" },contact: { title: "contact" },home: { title: "home" }
};

Paritial

Partial 的作用就是将某个类型里的属性全部变为可选项 ?。

Reuqired

Required 的作用就是将某个类型里的属性全部变为必选项。

Readonly

Readonly 的作用是将某个类型所有属性变为只读属性,也就意味着这些属性不能被重新赋值。

Exclude

Exclude<T, U> 的作用是将某个类型中属于另一个的类型移除掉。

type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"

Extract

Extract<T, U> 的作用是从 T 中提取出 U。

type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () => void

in

in 用来遍历枚举类型:

type Keys = "a" | "b" | "c"type Obj =  {[p in Keys]: any
} // -> { a: any, b: any, c: any }

TypeScript 编译原理

Scanner 扫描仪,Parser 解析器,Binder 绑定器,Checker 检查器,Emitter 发射器
TypeScript编译流程

面试题及实战

什么是类型推论,以下代码ts推论出的类型是什么

1、类型推论:指在编写TypeScript代码时,即使没有明确指定变量的类型,编译器也能根据上下文推断出变量的类型。这种类型推断机制使得TypeScript代码更加简洁,减少了需要显式声明类型的需要。
例如,如果声明一个变量但没有为其赋值,TypeScript会将其类型推断为any类型。但如果为变量赋了值,TypeScript会根据赋的值推断出更具体的类型,如字符串、数字等。这种类型推断的过程发生在初始化变量、设置默认参数值、决定函数返回值时,以及在需要确定变量类型的其他情况下。

let a = 1024; // number
let b = '1024'; // string 
const c = 'yhh'; // yhh, 使用const定义,会把该常量的类型进行收缩,收缩到具体的字面类型(这个类型只表示一个值)
let d = [true, false, true]; // boolean[]
let e = {name: 'yhh'}; // object 
let f = null; // any, 类型拓宽

类型推论
可赋值性:数组,布尔,数字,对象,函数,类,字符串,字面量类型,满足以下任一条件时,A类型可以赋值给B类型:
1、A是B的子类型
2、A是any的类型
规则2是规则1的例外

let aa = 1024;
let aa1 : number = 1024;
aa = aa1;
aa1 = aa;let bb : string = 'bb';
let bb1 : string | number = 'bb1';
bb = bb1;
bb1 = bb;
bb1 = 2;
// bb = bb1; // 不符合规则let i : 3 = 3;
// i = 4; // 不符合,i只能是3let j = [1,2,3];
j.push(4);
// j.push('5'); // 不符合,j只能是number类型// any类型可以赋值任何类型
let k : any = 1;
k = '1';
k = {name: 'yhh'};
k = null;
k = undefined;
k = 1;let n = []; // never[]
// n.push(1); // never类型不能push任何值let m; // any
m = []; // any
m.push(1); // any类型可以push任何值

2、类型断言:可以用来手动指定一个值的类型,即允许变量从一种类型更改为另一种类型
语法格式:<类型>值或 值 as 类型
在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用值 as 类型。

以下写法在编译时不会报错。但在运行时会报错,因为123为number,不用slice。
因此类型断言尽量避免使用,只在明确知道类型时可以使用。

function formatInput(input: string):string{return input.slice(0,10);
}
function getUserInput(): string | number{return 123;
}
let input = getUserInput();
formatInput(input as string);
formatInput(<string>input);

1. 你觉得使用ts的好处是什么?

1、TypeScript是JavaScript的加强版,它给JavaScript添加了可选的静态类型和基于类的面向对象编程,它拓展了JavaScript的语法。所以ts的功能比js只多不少.
2、Typescript 是纯面向对象的编程语言,包含类和接口的概念.
3、TS 在开发时就能给出编译错误, 而 JS 错误则需要在运行时才能暴露。
4、可以明确知道数据的类型。代码可读性极强,几乎每个人都能理解。
5、ts中有很多很方便的特性, 比如可选链.

2. type 和 interface的异同

重点:用interface描述数据结构,用type描述类型

2.1 都可以描述一个对象或者函数

interface User {name: stringage: number
}interface SetUser {(name: string, age: number): void;
}type User = {name: stringage: number
};type SetUser = (name: string, age: number)=> void;

2.2 都允许拓展(extends)

interface 和 type 都可以拓展,并且两者并不是相互独立的,也就是说 interface 可以 extends type, type 也可以 extends interface 。 虽然效果差不多,但是两者语法不同。

// interface extends interface
interface Name { name: string; 
}
interface User extends Name { age: number; 
}// type extends type
type Name = { name: string; 
}
type User = Name & { age: number  };// interface extends type
type Name = { name: string; 
}
interface User extends Name { age: number; 
}// type extends interface
interface Name { name: string; 
}
type User = Name & { age: number; 
}

2.3 只有type可以做的:声明基本类型别名,联合类型,元组等类型

type 可以声明基本类型别名,联合类型,元组等类型

// 基本类型别名
type Name = string// 联合类型
interface Dog {wong();
}
interface Cat {miao();
}type Pet = Dog | Cat// 具体定义数组每个位置的类型
type PetList = [Dog, Pet]// 当你想获取一个变量的类型时,使用 typeof
let div = document.createElement('div');
type B = typeof div

2.4 interface可以多次定义并被视为合并所有声明成员,type不支持

interface Point {x: number
}
interface Point {y: number
}
const point: Point = {x: 1, y: 2};interface User {name: string,age: number
}
interface User{id: number
}
// 最终合并为
const user: User = {name: 'yhh',age: 18,id: 1
}

2.5 type能使用in关键字生成映射类型,interface不行

type Keys = 'firstname' | 'surname';
type DudeType = {[key in Keys]: string;
}
const dude: DudeType = {firstname: 'y',surname: 'hh'
}

3. 如何基于一个已有类型, 扩展出一个大部分内容相似, 但是有部分区别的类型?

首先可以通过Pick和Omit

interface Test {name: string;sex: number;height: string;
}type Sex = Pick<Test, 'sex'>;const a: Sex = { sex: 1 };type WithoutSex = Omit<Test, 'sex'>;const b: WithoutSex = { name: '1111', height: 'sss' };

比如Partial, Required.

再者可以通过泛型.

4. 什么是泛型, 泛型的具体使用?

泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,使用时再去指定类型的一种特性。

可以把泛型理解为代表类型的参数

interface Test<T = any> {userId: T;
}type TestA = Test<string>;
type TestB = Test<number>;const a: TestA = {userId: '111',
};const b: TestB = {userId: 2222,
};

5. 写一个计算时间的装饰器

export function before(beforeFn: any) {return function(target: any, name: any, descriptor: any) {const oldValue = descriptor.value;descriptor.value = function() {beforeFn.apply(this, arguments);return oldValue.apply(this, arguments);};return descriptor;};
}export function after(afterFn: any) {return function(target: any, name: any, descriptor: any) {const oldValue = descriptor.value;descriptor.value = function() {const ret = oldValue.apply(this, arguments);afterFn.apply(this, arguments);return ret;};return descriptor;};
}
// 计算时间
export function measure(target: any, name: any, descriptor: any) {const oldValue = descriptor.value;descriptor.value = async function() {const start = Date.now();const ret = await oldValue.apply(this, arguments);console.log(`${name}执行耗时 ${Date.now() - start}ms`);return ret;};return descriptor;
}

6. 写一个缓存的装饰器

const cacheMap = new Map();export function EnableCache(target: any, name: string, descriptor: PropertyDescriptor) {const val = descriptor.value;descriptor.value = async function(...args: any) {const cacheKey = name + JSON.stringify(args);if (!cacheMap.get(cacheKey)) {const cacheValue = Promise.resolve(val.apply(this, args)).catch((_) => cacheMap.set(cacheKey, null));cacheMap.set(cacheKey, cacheValue);}return cacheMap.get(cacheKey);};return descriptor;
}

7. 实现一个路由跳转 通过ts约束参数的routeHelper

import { Dictionary } from 'vue-router/types/router';
import Router, { RoutePath } from '../router';export type BaseRouteType = Dictionary<string>;export interface IndexParam extends BaseRouteType {name: string;
}export interface AboutPageParam extends BaseRouteType {testName: string;
}export interface UserPageParam extends BaseRouteType {userId: string;
}export interface ParamsMap {[RoutePath.Index]: IndexParam;[RoutePath.About]: AboutPageParam;[RoutePath.User]: UserPageParam;
}export class RouterHelper {public static replace<T extends RoutePath>(routePath: T, params: ParamsMap[T]) {Router.replace({path: routePath,query: params,});}public static push<T extends RoutePath>(routePath: T, params: ParamsMap[T]) {Router.push({path: routePath,query: params,});}
}

8. 实现一个基于ts和事件模式的countdown基础类

import { EventEmitter } from 'eventemitter3';export interface RemainTimeData {/** 天数 */days: number;/*** 小时数*/hours: number;/*** 分钟数*/minutes: number;/*** 秒数*/seconds: number;/*** 毫秒数*/count: number;
}export type CountdownCallback = (remainTimeData: RemainTimeData, remainTime: number) => void;enum CountdownStatus {running,paused,stoped,
}
// 练习
interface User {name: stringage: number
}
function test<T extends User>(params: T): T{return params
}
test({name:'1',age:1});export enum CountdownEventName {START = 'start',STOP = 'stop',RUNNING = 'running',
}
interface CountdownEventMap {[CountdownEventName.START]: [];[CountdownEventName.STOP]: [];[CountdownEventName.RUNNING]: [RemainTimeData, number];
}export function fillZero(num: number) {return `0${num}`.slice(-2);
}export class Countdown extends EventEmitter<CountdownEventMap> {private static COUNT_IN_MILLISECOND: number = 1 * 100;private static SECOND_IN_MILLISECOND: number = 10 * Countdown.COUNT_IN_MILLISECOND;private static MINUTE_IN_MILLISECOND: number = 60 * Countdown.SECOND_IN_MILLISECOND;private static HOUR_IN_MILLISECOND: number = 60 * Countdown.MINUTE_IN_MILLISECOND;private static DAY_IN_MILLISECOND: number = 24 * Countdown.HOUR_IN_MILLISECOND;private endTime: number;private remainTime: number = 0;private status: CountdownStatus = CountdownStatus.stoped;private step: number;constructor(endTime: number, step: number = 1e3) {super();this.endTime = endTime;this.step = step;this.start();}public start() {this.emit(CountdownEventName.START);this.status = CountdownStatus.running;this.countdown();}public stop() {this.emit(CountdownEventName.STOP);this.status = CountdownStatus.stoped;}private countdown() {if (this.status !== CountdownStatus.running) {return;}this.remainTime = Math.max(this.endTime - Date.now(), 0);this.emit(CountdownEventName.RUNNING, this.parseRemainTime(this.remainTime), this.remainTime);if (this.remainTime > 0) {setTimeout(() => this.countdown(), this.step);} else {this.stop();}}private parseRemainTime(remainTime: number): RemainTimeData {let time = remainTime;const days = Math.floor(time / Countdown.DAY_IN_MILLISECOND);time = time % Countdown.DAY_IN_MILLISECOND;const hours = Math.floor(time / Countdown.HOUR_IN_MILLISECOND);time = time % Countdown.HOUR_IN_MILLISECOND;const minutes = Math.floor(time / Countdown.MINUTE_IN_MILLISECOND);time = time % Countdown.MINUTE_IN_MILLISECOND;const seconds = Math.floor(time / Countdown.SECOND_IN_MILLISECOND);time = time % Countdown.SECOND_IN_MILLISECOND;const count = Math.floor(time / Countdown.COUNT_IN_MILLISECOND);return {days,hours,minutes,seconds,count,};}
}

使用

<template><div class="home" @click="toAboutPage"><img alt="Vue logo" src="../assets/logo.png"><HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/><div>倒计时:{{timeDisplay}}</div></div>
</template><script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from '../components/HelloWorld.vue';
import { RouterHelper } from '../lib/routerHelper';
import { Countdown, CountdownEventName, fillZero } from '../lib/countdown';
import { RoutePath } from '../router';
import { measure } from '../decorator';@Component({components: {HelloWorld,},
})
export default class Home extends Vue {public timeDisplay: string = '';@measurepublic toAboutPage() {RouterHelper.push(RoutePath.About, {  testName: '1111' });}public created() {const countdown = new Countdown(Date.now() + 60 * 60 * 1000, 10);countdown.on(CountdownEventName.RUNNING, (remainTimeData) => {const { hours, minutes, seconds, count} = remainTimeData;this.timeDisplay = [hours, minutes, seconds, count].map(fillZero).join(':');});}
}
</script>

9. npm install一个模块,都发生了什么

npm install命令输入 > 检查node_modules目录下是否存在指定的依赖 > 如果已经存在则不必重新安装 > 若不存在,继续下面的步骤 > 向 registry(本地电脑的.npmrc文件里有对应的配置地址)查询模块压缩包的网址 > 下载压缩包,存放到根目录里的.npm目录里 > 解压压缩包到当前项目的node_modules目录中。

10. eventemitter3

TypeScript 编译器提供了两个发射器:

emitter.ts: 它是 TS -> JavaScript 的发射器
declarationEmitter.ts: 用于为 TypeScript 源文件(.ts) 创建声明文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/386080.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

按图搜索新体验:阿里巴巴拍立淘API返回值详解

阿里巴巴拍立淘API是一项基于图片搜索的商品搜索服务&#xff0c;它允许用户通过上传商品图片&#xff0c;系统自动识别图片中的商品信息&#xff0c;并返回与之相关的搜索结果。以下是对阿里巴巴拍立淘API返回值的详细解析&#xff1a; 一、主要返回值内容 商品信息 商品列表…

【算法/学习】前缀和差分

前缀和&&差分目录 1. 前缀和的概念及作用 &#x1f308;概念 &#x1f308;用途 &#x1f319;一维前缀和 &#x1f319;二维前缀和 2. 差分的概念及用途 &#x1f308;概念&#xff1a; &#x1f308;用途 &#x1f319;一维差分 &#x1f319;二维差分 1. …

Linux系统编程——线程池

目录 一&#xff0c;池化技术 二&#xff0c;线程池概念 三&#xff0c;线程池实现 3.1 线程封装 3.2 预备头文件实现 3.3 线程池类的简单实现 3.4 主函数实现 3.5 效果展示 一&#xff0c;池化技术 池化技术是计算机编程领域非常常用的一种技术&#xff0c;该技术可以…

【前端/js】使用js读取本地文件(xml、二进制)内容

目录 说在前面FileReaderDOMParser文本文件二进制文件 说在前面 浏览器版本&#xff1a;Microsoft Edge 126.0.2 (正式版本) (64 位) FileReader MDNFileReader 接口允许 Web 应用程序异步读取存储在用户计算机上的文件&#xff08;或原始数据缓冲区&#xff09;的内容&#x…

CL4056D 1A锂离子电池线性充电器芯片IC

一般描述 CL4056D是一款ESOP8封装的独立线性锂离子电池充电器。由于外部元件较少&#xff0c;因此CL4056D非常适合用于各种便携式应用。充电电流可以通过外部电阻器进行编程。在待机模式下&#xff0c;供电电流将降低到约35uA。当输入电压断开时&#xff0c;CL4056 D将进…

UWA Gears正式上线,助力移动平台性能优化

亲爱的开发者朋友们&#xff0c; 我们非常激动地向大家宣布&#xff0c;UWA最新的无SDK性能分析工具 - UWA Gears&#xff0c;现已正式发布&#xff01;无论您使用的是哪种开发引擎&#xff0c;这款工具都能轻松应对&#xff0c;为您的项目保驾护航。更令人心动的是&#xff0c…

Lua编程

文章目录 概述lua数据类型元表注意 闭包表现 实现 lua/c 接口编程skynet中调用层次虚拟栈C闭包注册表userdatalightuserdata 小结 概述 这次是skynet&#xff0c;需要一些lua/c相关的。写一篇博客&#xff0c;记录下。希望有所收获。 lua数据类型 boolean , number , string…

在react中如何计算本地存储体积

1.定义useLocalStorageSize钩子函数 // 计算localStorage大小 function useLocalStorageSize() {const [size, setSize] useState(0);useEffect(() > {const calculateSize () > {let totalSize 0;for (let key in localStorage) {//过滤掉继承自原型链的属性if (loc…

Redis是多线程还是单线程?

文章目录 1、用户态和内核态2、阻塞IO3、非阻塞IO4、IO多路复用4.1 select4.2 poll4.3 epoll4.4 epoll中的ET和LT4.5 epoll的服务端流程 5、信号驱动6、异步IO7、对比8、Redis是单线程的吗&#xff1f;9、单线程多线程网络模型变更 1、用户态和内核态 1、ubuntu和Centos 都是Li…

基于PaddleClas的人物年龄分类项目

目录 一、任务概述 二、算法研发 2.1 下载数据集 2.2 数据集预处理 2.3 安装PaddleClas套件 2.4 算法训练 2.5 静态图导出 2.6 静态图推理 三、小结 一、任务概述 最近遇到个需求&#xff0c;需要将图像中的人物区分为成人和小孩&#xff0c;这是一个典型的二分类问题…

Python | Leetcode Python题解之第283题移动零

题目&#xff1a; 题解&#xff1a; class Solution:def moveZeroes(self, nums: List[int]) -> None:n len(nums)left right 0while right < n:if nums[right] ! 0:nums[left], nums[right] nums[right], nums[left]left 1right 1

ClickHouse 进阶【建表、查询优化】

1、ClickHouse 进阶 因为上一节部署了集群模式&#xff0c;所以需要启动 Zookeeper 和 ck 集群&#xff1b; 1.1、Explain 基本语法 EXPLAIN [AST | SYNTAX | PLAN | PIPELINE] [setting value, ...] SELECT ... [FORMAT ...] AST&#xff1a;用于查看语法树SYNTAX&#…

橙单后端项目下载编译遇到的问题与解决

今天下载orange-admin项目&#xff0c;不过下载下来运行出现一些问题。 1、涉及到XMLStreamException的几个类都出现下面的错误 The package javax.xml.stream is accessible from more than one module: <unnamed>, java.xml ctrl-shift-t 可以找到这个引入是哪些包里…

成为git砖家(5): 理解 HEAD

文章目录 1. git rev-parse 命令2. 什么是 HEAD2.1 创建分支当并未切换&#xff0c; HEAD 不变2.2 切换分支&#xff0c;HEAD 改变2.3 再次切换分支&#xff0c; HEAD 再次改变 3. detached HEAD4. HEAD 表示分支、表示 detached HEAD 有什么区别&#xff1f;区别相同点 5. HEA…

【SpringCloud】企业认证、分布式事务,分布式锁方案落地-2

目录 高并发缓存三问 - 穿透 缓存穿透 概念 现象举例 解决方案 缓存穿透 - 预热架构 缓存穿透 - 布隆过滤器 布隆过滤器 布隆过滤器基本思想​编辑 了解 高并发缓存三问 - 击穿 缓存击穿 高并发缓存三问 - 雪崩 缓存雪崩 解决方案 总结 为什么要使用数据字典&…

Python网络爬虫:基础与实战!附淘宝抢购源码

Python网络爬虫是一个强大的工具&#xff0c;用于从互联网上自动抓取和提取数据。下面我将为你概述Python网络爬虫的基础知识和一些实战技巧。 Python网络爬虫基础 1. HTTP请求与响应 网络爬虫的核心是发送HTTP请求到目标网站并接收响应。Python中的requests库是处理HTTP请求…

Java NIO (一)

因工作需要我接触到了netty框架&#xff0c;这让我想起之前为夺高薪而在CSDN购买的Netty课程。如今看来&#xff0c;这套课程买的很值。这套课程中关于NIO的讲解&#xff0c;让我对Tomcat产生了浓厚的兴趣&#xff0c;于是我阅读了Tomcat中关于服务端和客户端之间连接部分的源码…

乐尚代驾六订单执行一

加载当前订单 需求 无论是司机端&#xff0c;还是乘客端&#xff0c;遇到页面切换&#xff0c;重新登录小程序等&#xff0c;只要回到首页面&#xff0c;查看当前是否有正在执行订单&#xff0c;如果有跳转到当前订单执行页面 之前这个接口已经开发&#xff0c;为了测试&…

JAVAWeb实战(后端篇)

因为前后端代码内容过多&#xff0c;这篇只写后端的代码&#xff0c;前端的在另一篇写 项目实战一&#xff1a; 1.创建数据库,表等数据 创建数据库 create database schedule_system 创建表&#xff0c;并添加内容 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------…

Node.js版本管理工具之NVM

目录 一、NVM介绍二、NVM的下载安装1、NVM下载2、卸载旧版Node.js3、安装 三、NVM配置及使用1、设置nvm镜像源2、安装Node.js3、卸载Node.js4、使用或切换Node.js版本5、设置全局安装路径和缓存路径 四、常用命令技术交流 博主介绍&#xff1a; 计算机科班人&#xff0c;全栈工…