当前位置: 首页 > news >正文

typeScript学习笔记(一)

学习资源来自:

类与接口 · TypeScript 入门教程 (xcatliu.com) 

一.TypeScript的安装和运行

1.安装TypeScript

  • 通过npm(Node.js包管理器)
  • 安装Visual Studio的TypeScript插件:(Visual Studio 2017和Visual Studio 2015 Update 3默认包含了TypeScript。 如果你的Visual Studio还没有安装TypeScript)

2.npm安装TypeScript

  • 安装教程 TypeScript环境搭建,并且部署到VSCode(亲测有效)_咖啡壶子的博客-CSDN博客
  • 安装过程中问题:

TypeScript- 解决(tsc 不是内部或外部命令,也不是可运行的程序或批处理文件)问题 - sanyekui - 博客园 (cnblogs.com)

3.将环境安装好之后,就可以尝试构建第一个typeScript程序

  • 新建Demo.ts文件
function greeter(person: string) {return 'Hello, ' + person
}let user = 'Jane User'document.body.innerHTML = greeter(user)
  • 在终端输入: 
    tsc greeter.ts
  • 就会输出一个 包含和输入内容一样的JavaScript代码

      

  • 新建文件demo.html 
<!DOCTYPE html>
<html><head><title>TypeScript Greeter</title></head><body><script src="demo.js"></script></body>
</html>
  •    执行结果会展示在界面上

二.基础类型

1.布尔值

  • true 或者 false
  • 在JS或者TS中叫boolean
  • 语法: let boolean = false
  • 注意:使用Boolean 创造的对象不是布尔值,比如:let createdByNewBoolean: Boolean = new Boolean(1);
  • 直接调用Boolean 也可以返回一个 boolean类型 let createdByBoolean: boolean = Boolean(1);
  • 在TypeScript中,boolean 是基本类型,Boolean 是构造函数 

2.数字类型

  • TypeScript里面所有数字都是浮点数,这些浮点数的类型是Number
  • 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015 中引入的二进制和八进制
  • 二进制表示法:let binaryLiteral: number = 0b1010;
  • 八进制表示法:let octalLiteral: number = 0o744;
  • 二进制和八进制会被编译为十进制数字      

3.字符串

  • 使用string表示
  • 用单引号或者双引号包起来
  • 可以使用模板字符串 ${`XXX`}

4.数组

  • let list:number[] = [1, 2, 3]
  • let list:Array<number> = [1, 2, 3]

5.元组Tuple

  • 表示一个已知元素数量和类型的数组
  • 各个元素的类型不一定相同
  • let x:[string, number]
  • x = ['hello', 10]

6.枚举

  • enum类型是对JavaScript标准数据类型的一个补充
enum Color {Red,Green,Blue,
}
let c: Color = Color.Green
  • 默认情况下,从0开始为元素编号,可以手动指定成员的数值

enum Color {Red = 1,Green,Blue,
}
let c: Color = Color.Green
console.log(c) // 2
  • 全部采用手动赋值

enum Color {Red = 1,Green = 2,Blue = 4,
}
let c: Color = Color.Blue
console.log(c) // 4
  • 找出映射的名字

enum Color {Red = 1,Green,Blue,
}
let colorName: string = Color[2]
console.log(colorName) // Green

7.任意值 any

  • 需要在编译阶段还不清楚的变量指定一个类型
  • 不希望类型检查器对这些值进行检查,而是直接让它们通过编译阶段的检查
  • 就可以使用any类型来标记这些变量
  • 注意:Object类型的变量只是允许你给他赋任意值,却不能够在它上面调用任意的方法
  • 当你只知道一部分数据的类型时,any类型也是有用的, 比如:
    let list: any[] = [1, true, "free"]
  • 声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值

  • 在声明的之后,未指定其类型,就会被识别为任意值类型

8.空值 void

  • 表示没有任何类型
  • 当一个函数没有返回值时,就会见到void
  • 声明一个void变量没什么用,因为你只能赋予它undefined 和 null

9.null和undefined

  • 与void的区别是,undefined和null是所有类型的子类型,也就是说undefined类型的变量可以赋值给所有类型
  • void的类型不可以

10.never

  • never类型标识永不存在的值的类型
  • never类型是那些总是会抛出异常,或者根本不会有返回值的函数表达式或箭头函数表达式的返回值类型
  • 变量也可能是never类型,当它们被永不为真的类型保护所约束的时候
  • never类型是任何类型的子类型:可以赋值给任何类型
  • 没有类型是never的子类型,就是只能将never类型赋值给never类型
  • any也不可以赋值给never
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {throw new Error(message);
}// 推断的返回值类型为never
function fail() {return error("Something failed");
}// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {while (true) {}
}

12.联合类型

  • 表示取值可以为多种类型中的一种
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
  • 联合类型使用 | 分隔每个类型

  • let myFavoriteNumber: string | number;  的含义是允许 myFavoriteNumber 是string类型或者number类型,但是不能是其他类型

  • 当TypeScript不确定一个联合类型的变量到底是哪个类型的时候,只能访问此联合类型中所有属性里共有的属性和方法

11.类型断言

  • 类型断言就相当其他语言中的类型转换(显示转换)
  • 但是不进行特殊的数据检查和解构
  • 没有运行时的影响,只是在编译阶段起作用

  两种形式:

  • 尖括号语法
let someValue: any = 'this is a string'
let strLength: number = (<string>someValue).length
  • as 语法
let someValue: any = 'this is a string'
let strLength: number = (someValue as string).length

12.类型推论

下面代码虽然没有指定类型,但是在编译的时候会报错,TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论

let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
  • 如果在定义的时候没有赋值,不管之后有没有赋值,都会被推断为any类型而不被类型检查

三.变量声明

① var和let声明与JavaScript中一致

  • var 声明可以在包含它的函数,模块,命名空间或者全局作用域内部任何位置被访问
  • let 支持块作用域,在声明之前读或者写
  • var可以多次声明,只会取最后一个
  • let如果多次声明就会报错
  • 使用let替换var

② const 声明

  • 赋值后不能被改变
  • 和let的作用域规则相同,但是不能对它们重新赋值
  • 但是可以修改对象内部的值

③ let 和 const 的选择

  • 使用最小特权原则,所有变量除了你计划去修改的都应该使用const
  • 如果需要修改就使用let

④ 解构

解构数组

  • 最简单的解构数组
let input = [1, 2]
let [first, second] = input
console.log(first)
console.log(second)
  • 利用解构交换两个变量的值

let input = [1, 2]
let [first, second] = input
;[first, second] = [second, first]console.log(first)
console.log(second)
  • 解构用在函数参数上
let input = [1, 2]
function f([first, second]: number[]) {console.log(first)console.log(second)
}
f(input)
  • 使用剩余参数解构

let [first, ...rest] = [1, 2, 3, 4]
console.log(first)
console.log(rest)
  • 只解构其中一个数据
let [first] = [1, 2, 3, 4]
console.log(first)
  • 将不关心的元素省略

let [, second, , fourth] = [1, 2, 3, 4]
console.log(second)

  解构对象

let o = {a: 'foo',b: 12,c: 'bar',
}
let { a, b } = o
console.log(a)
console.log(b)
  • 属性重命名

let o = {a: 'foo',b: 12,c: 'bar',
}
let { a: name1, b: name2 } = o
console.log(name1)
console.log(name2)
  • 默认值

  • 参数默认值(如果函数没有传参数,就使用初始化列表中的值)

  • 解构表达还是要尽量保持小而简单

⑤ 展开运算符

  • 允许将一个数组展开为另一个数组
let first = [1, 2]
let second = [3, 4]
let bothPlus = [0, ...first, ...second, 5]
console.log(bothPlus) // [0, 1, 2, 3, 4, 5]
  • 将一个对象展开为另一个对象
let defaults = { food: 'spicy', price: '$$', ambiance: 'noisy' }
let bothPlus = { ...defaults, food: 'rich' }
console.log(bothPlus) //

四.接口

  • 在TypeScript中,使用接口(Interfaces)来定义对象的类型
  • 在TypeScript中,除了可用于对类的一部分行为进行抽象以外,也常用于对【对象的形状】进行描述
  • TypeScript核心原则:对值所具有的结构进行类型检查
  • 接口的作用是为这些类型命名和为你的代码或第三方代码定义契约
  • 下面的例子:定义了一个接口,接着定义了一个变量tom,类型是Person,  约束tom的形状必须和接口 Person 一致
  • 定义的变量比接口少了一些属性或者多了一些属性都不被允许,必须和接口的形状保持一致

      

 

  • 可选属性

    ① 有时候希望不要完全匹配一个形状,可以用可选属性

    ② 可选属性的含义就是该属性可以不存在

    ③ 但是仍然不允许添加未定义的属性

  

  • 任意属性  

     ① 有时候我们希望一个接口允许有任意的属性,上面是使用 [propName: string]  定义了任意属性取string 类型的值

    ② 一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集

    ③ 所以下面的案例中,如果任意属性中的值允许是string, 但是可选属性age的值是number,不是string的子属性,所以报错了

④ 一个接口中只能定义一个任意属性,如果接口中有多个类型的属性,则可以在任意属性中使用联合类型

  • 只读属性

  ① 有时候我们希望对象中的一些字段只能在创建的时候被赋值,就使用 readonly 定义只读属性

  ② 只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

  ③ 只读属性不能进行赋值(无法修改)

interface Point {readonly x: numberreadonly y: number
}let p1: Point = { x: 10, y: 10 }
p1.x = 10   // 会报错,属性是只读属性

③ 只读属性在第一次初始化对象的时候,必须进行初始化

 

  • 数组只读属性

let a: number[] = [1, 2, 3, 4]
// 限制数组是只读类型
let ro: ReadonlyArray<number> = aro[0] = 1 // 报错
  • readonly 和 const

    ① 作为变量使用的话就用const

    ② 作为属性就使用  readonly

  •  额外的属性检查

解决方法 ① 

解决方法 ② :添加一个字符串索引签名

解决方法③ 将这个对象赋值给另一个变量,不会经过额外属性检查

五.数组类型

   ①【类型 + 方括号】表示法

let fibonacci: number[] = [1, 1, 2, 3, 5];

  ② 数组的项中不允许出现其他类型

     

  ③ 数组中的一些方法的参数也会根据数组在定义时约定的类型进行限制

   

④ 可以使用数组泛型   Array<elemType>  来表示数组

let fibonacci: Array<number> = [1, 1, 2, 3, 5];

⑤ 用接口表示数组

interface NumberArr {[index: number]: number
}
let fib: NumberArr = [1, 2, 3, 4]

   用接口表示数组比较少见,但是经常用它表示类数组(伪数组)

    

使用普通数组不能定义为数组,所以使用接口的形式

   

常用的类数组都有自己的接口定义,比如 IArgumentsNodeListHTMLCollection

function sum() {let args: IArguments = arguments
}

IArgument 是TypeScript定义好的类型,实际上就是

interface IArguments {[index: number]: any;length: number;callee: Function;
}

⑥ any在数组中的应用:any表示数组中允许出现任意类型

let list: any[] = ['xcatliu', 25, { website: 'http://xcatliu.com' }];

六.函数的类型

① 函数声明:

  • 输入多余或者少于的参数,是不被允许的
function sum(x: number, y: number): number {return x + y;
}

②  函数表达式

let mySum: (x: number, y: number) => number = function (x: number, y: number): number {return x + y;
};

TypeScript 中的 => 和 ES6中的箭头不一样,TypeScript中,=>用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型

③ 用接口定义函数的形状

interface SearchFunc {(source: string, subString: string): boolean
}let mySearch: SearchFunc
mySearch = function (source: string, subString: string) {return source.search(subString) !== -1
}
  • 用函数表达式或者接口定义函数时,对等号左侧进行类型限制,可以保证对函数名赋值时保证参数的个数,参数类型和返回值类型不变

④ 可选参数

  • 在参数名后面加问号
  • 可选参数后面不允许再出现必选参数

⑤ 参数默认值

  • 允许给函数添加默认值,TypeScript会将添加了默认值的参数识别为可选参数
  • 不受【可选参数必须在必选参数后面】限制了

⑥ 剩余参数

  • ...rest的方式获取函数中的剩余参数
  • rest只能是最后一个参数
function push(array: any[], ...items: any[]) {items.forEach(function (item) {array.push(item)})
}let a: any[] = []
push(a, 1, 2, 3)

⑦ 重载

  • 重载允许一个函数接受不同数量或类型的参数时,作出不同的处理
  • 注意:多个函数定义如果有包含关系,需要优先把精确的定义写在前面,因为TypeScript会优先从最前面的函数定义开始匹配
function reverse(x: number): number
function reverse(x: string): string
function reverse(x: number | string): number | string | void {if (typeof x === 'number') {return Number(x.toString().split('').reverse().join(''))} else if (typeof x === 'string') {return x.split('').reverse().join('')}
}

七.类型断言

① 概念

  • 类型断言含义:可以手动指定一个值类型

  • 语法:值 as 类型     <类型>值

  • 在 tsx(React 的 jsx 语法的 ts 版)  语法中必须使用前者

  • <类型>这种语法在ts中除了表示类型断言之外,也有可能是表示一个泛型

  • 所以在使用断言的时候,统一使用 值 as 这样的语法

② 类型断言的用途

(1) 将一个联合类型断言为其中一个类型

  • 此时可以使用类型断言,将 animal 断言成 Fish

  • 使用断言的时候一定要格外小心,尽量避免断言后调用方法或者引用深层属性,减少不必要的运行时的错误

(2)将一个父类断言为更加具体的子类

(3)将任何一个类型断言为any

  • 在any类型的变量上,访问任何属性都是允许的
  • 但是它可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用as any
  • 不能滥用 as any, 也不要完全否定它的作用,需要在类型的严格性和开发的便利性之间掌握平衡

(4)将as断言为一个具体的类型

  • 明确tom的类型之后,提高代码的可维护性

总结

  • 联合类型可以被断言为其中一个类型
  • 父类可以被断言为子类
  • 任何类型都可以被断言为any
  • any可以被断言为任何类型

③ 类型断言的限制

  • 并不是任何一个类型都可以被断言为任何另一个类型
  • 如果A兼容B,那么A能够被断言成B, B也能被断言成A
interface Animal {name: string
}
interface Cat {name: stringrun(): void
}function testAnimal(animal: Animal) {return animal as Cat
}
function testCat(cat: Cat) {return cat as Animal
}
  • 允许animal as Cat 是因为 [父类可以被断言为子类]
  • 允许cat as Animal 是因为既然子类拥有父类的属性和方法,那么被断言为父类,获取父类的方法,就不会有任何问题,所以子类可以被断言为父类
  • 要使A能够被断言成B, 只需要A兼容B或者B兼容A即可

综上所述:

  • 联合类型可以被断言为其中一个类型
  • 父类可以被断言为子类
  • 任何类型都可以被被断言为any
  • any可以被断言为任何类型
  • 要使得 A 能够被断言为 B,只需要 A 兼容 B 或 B 兼容 A 即可

④ 双重断言

interface Cat {run(): void
}
interface Fish {swim(): void
}function testCat(cat: Cat) {return cat as any as Fish
}
  • 会导致运行时错误,除非迫不得已,千万别使用双重断言

⑤ 类型断言和类型转换

  • 类型断言只会影响到TypeScript编译时的类型,类型断言语句在编译结果中会被删除

  • 类型断言不是类型转换,它不会真的影响到变量的类型
  • 如果要进行类型转换,需要直接调用类型转换的方法

 

 ⑥ 类型断言和类型声明

类型断言

 

  • animal断言为Cat,只需要满足Animal 兼容 Cat 或 Cat 兼容 Animal 即可
  • animal赋值为Cat, 需要满足Cat兼容Animal才行,但是Cat并不兼容Animal
  • 类型声明比类型断言更加严格,最好优先使用类型声明

⑦ 类型断言和泛型

  •  更加规范的实现对 getCacheData 返回值的约束
  • 同时去掉了代码中的any,是最优的一个解决方案
function getCacheData<T>(key: string): T {return (window as any).cache[key]
}interface Cat {name: stringrun(): void
}const tom = getCacheData<Cat>('tom')
tom.run()

八. 声明文件

① 当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全,接口提示等功能

② 声明语句

③ 声明文件:把声明语句放到一个单独的文件中

文件以 .d.ts 为结尾 ,其他所有*.ts文件就可以获得 jQuery 的类型定义了

declare var jQuery: (selector: string) => any;

④ 第三方声明文件

  • 使用 @type 统一管理第三方库的声明文件
  • 直接使用npm 安装对应的声明模块 
    npm install @types/jquery --save-dev

⑤ 书写声明文件

库的使用场景:

  • 全局变量:通过<script>标签引入第三方库,注入全局变量
  • npm: 通过 import foo from 'foo' 导入,符合ES6模块规范
  • UMD 库:既可以通过 <script> 标签引入,又可以通过 import 导入
  • 直接扩展全局变量:通过 <script> 标签引入后,改变一个全局变量的结构
  • 在 npm 包或 UMD 库中扩展全局变量:引用 npm 包或 UMD 库后,改变一个全局变量的结构
  • 模块插件:通过 <script> 或 import 导入后,改变另一个模块的结构

(1)全局变量

declare var/let/const

  • 定义全局变量
  • 使用 declare var 和 declare let 没有区别
  • 使用 declare const 时,表示此时的全局变量是一个常量,不允许再修改它的值了
  • 一般来说,全局变量都是禁止修改的常量,所以大部分情况都应该使用const而不是var 或者 let
  • 声明语句中只能定义类型,不要定义具体的实现

declare function

  • 定义全局函数 
  • declare function jQuery(selector: string): any;
  • 函数类型的声明语句中,函数重载也是支持的

declare function jQuery(selector: string): any;
declare function jQuery(domReadyCallback: () => any): any;

declare class

  • 定义的全局变量是一个类
  • declare class Animal {name: string;constructor(name: string);sayHi(): string;
    }
  •  只能用来定义类型,不能用来定义具体的实现

declare enum

  • 定义枚举类型,也被称为外部枚举
declare enum Directions {Up,Down,Left,Right
}
  • declare enum 仅用来定义类型,而不是具体的值

declare namespace

  • 用来表示全局变量是一个对象,包含很多子属性
declare namespace jQuery {function ajax(url: string, settings?: any): void;const version: number;class Event {blur(eventType: EventType): void}enum EventType {CustomClick}
}
jQuery.ajax('/api/get_something');

嵌套的命名空间

  • 如果对象拥有深层的层级,需要使用嵌套的 namespace 来声明深层的属性的类型
declare namespace jQuery {function ajax(url: string, settings?: any): void;namespace fn {function extend(object: any): void;}
}jQuery.ajax('/api/get_something');
jQuery.fn.extend({check: function() {return this.each(function() {this.checked = true;});}
});
  • 如果 jQuery 下仅有fn这一个属性,可以不需要嵌套  namespace

declare namespace jQuery.fn {function extend(object: any): void;
}jQuery.fn.extend({check: function() {return this.each(function() {this.checked = true;});}
});

interface 和 type

  • 声明一个全局的接口或者类型
  • interface AjaxSettings {method?: 'GET' | 'POST'data?: any;
    }
    declare namespace jQuery {function ajax(url: string, settings?: AjaxSettings): void;
    }// src/index.tslet settings: AjaxSettings = {method: 'POST',data: {name: 'foo'}
    };
    jQuery.ajax('/api/post_something', settings);
  • type 与 interface类似

防止命名冲突

  • 暴露在外层 interface 或 type 会作为全局类型作用于整个项目中,应该尽可能减少全局变量或全局类型的数量
  • 所以将他们最好放到 namespace 下
declare namespace jQuery {interface AjaxSettings {method?: 'GET' | 'POST'data?: any;}function ajax(url: string, settings?: AjaxSettings): void;
}
  • 在使用interface的时候,也应该加上 jQuery 前缀

let settings: jQuery.AjaxSettings = {method: 'POST',data: {name: 'foo'}
};
jQuery.ajax('/api/post_something', settings);

声明合并

  •  假如 jQuery 既是一个函数,可以直接被调用 jQuery('#foo'),又是一个对象,拥有子属性 jQuery.ajax()(事实确实如此),那么可以组合多个声明语句,他们会不冲突的合并起来
declare function jQuery(selector: string): any;
declare namespace jQuery {function ajax(url: string, settings?: any): void;
}jQuery('#foo');
jQuery.ajax('/api/get_something');

npm 包

九.内置对象

① ECMAScript  标准提供的内置对象:BooleanErrorDateRegExp,可以在TypeScript中定义以下类型

let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred');
let d: Date = new Date();
let r: RegExp = /[a-z]/;

② DOM和BOM的内置对象

  • DocumentHTMLElementEventNodeList,TypeScript中会经常用到这些类型

③ TypeScript核心库的定义文件

  • 定义了所有浏览器环境需要用到的类型,并且是预置在 TypeScript中
  • 当使用一些常用的方法的时候,TypeScript实际上已经帮你做了很多类型判断的工作
  • TypeScript 核心库的定义中不包含 Node.js 部分
  • 如果想用TypeScript写Node.js,需要引入第三方声明文件 
    npm install @types/node --save-dev

十.类型别名

  • 就是给类型起一个别的名字
  • 使用type创建类型别名
  • 类型别名常用于联合类型
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {if (typeof n === 'string') {return n;} else {return n();}
}

十一.字符串字面量类型

  • 用来约束取值只能是某几个字符串中的一个
  • 使用type定了一个 字符串字面量类型 EventNames, 只能取三种字符串中的一种
  • 类型别名和字符串字面量类型都是type进行定义的
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {// do something
}handleEvent(document.getElementById('hello'), 'scroll');  // 没问题
handleEvent(document.getElementById('world'), 'dblclick'); // 报错,event 不能为 'dblclick'

十二.元组

  • 数组合并了相同类型的对象,元组合并了不同类型的对象
let tom: [string, number] = ['Tom', 25];
let tom: [string, number];
tom[0] = 'Tom';
tom[1] = 25;tom[0].slice(1);
tom[1].toFixed(2);
  • 也可以赋值其中一项

let tom: [string, number];
tom[0] = 'Tom';
  • 直接对元组类型变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项

  • 越界的元素

① 当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型

十三.枚举

  • 枚举类型用于取值被限定在一定范围内的场景
  • 使用enum关键字来定义
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
  • 手动赋值

     ① 未手动赋值的枚举项会接着上一个枚举递增

     ② 如果未手动赋值的枚举项与手动赋值的重复了,TypeScript是不会报错的

     ③ 所以使用的时候要注意,最好不要有这种情况 

enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};

     ④ 手动赋值的枚举项可以不是数字,这个时候需要使用类型断言来让tsc无视类型检查

enum Days {Sun = 7, Mon, Tue, Wed, Thu, Fri, Sat = <any>"S"};

     ⑤ 手动赋值的枚举项也可以是小数或者负数,未赋值的项逐步增长1

  • 常数项和计算所得项

   ① 枚举项有两种类型,常数项和计算所得项

    常数项:上面的例子就是常数项

    计算所得项:Blue = "blue".length

enum Color {Red, Green, Blue = "blue".length};

② 但是如果紧接在计算所得项后面的是未手动赋值的项,就会因为无法获得初始值而报错

③ 当满足以下条件时,枚举成员被当作是常数

  •  不具有初始化函数并且之前的枚举成员是常数:当前枚举成员的值等于上一个枚举成员的值 + 1,第一个枚举元素的值是0
  • 枚举成员使用常数枚举表达式初始化

数字字面量,引用之前定义的常数枚举成员, 带括号的常数枚举表达式, +-~ 一元运算符应用于常数枚举表达式; +-*/%<<>>>>>&|^ 二元运算符,常数枚举表达式做为其一个操作对象

所有其他情况的枚举成员被当作是需要计算得出的值

④ 常数枚举

  • 使用 const enum 定义的枚举类型
const enum Directions {Up,Down,Left,Right
}let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
  • 与普通枚举的区别是,会在编译阶段被删除,并且不能包含计算成员

⑤ 外部枚举

  • 外部枚举是使用 declare enum 定义的枚举类型
declare enum Directions {Up,Down,Left,Right
}let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
  • declare和const可以同时使用

declare const enum Directions {Up,Down,Left,Right
}let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];

相关文章:

typeScript学习笔记(一)

学习资源来自&#xff1a; 类与接口 TypeScript 入门教程 (xcatliu.com) 一.TypeScript的安装和运行 1.安装TypeScript 通过npm&#xff08;Node.js包管理器&#xff09;安装Visual Studio的TypeScript插件:(Visual Studio 2017和Visual Studio 2015 Update 3默认包含了Ty…...

第4章:网络层

文章目录 一、概述和功能2.SDN二、转发1.IP数据报(1)IP数据报的首部字段(2)IP数据报的分片2.IPv4地址:<网络号>,<主机号>3.IP编址 (三个历史阶段)(1)分类IP地址①特殊IP地址②私有IP地址③网络地址转换NAT:导致IP地址变化MAC地址、IP地址变化问题(2)子网划分与子…...

C高级day1 shell 指令的补充学习

使用cut截取出Ubuntu用户的家目录&#xff0c;要求&#xff1a;不能使用":"作为分割 2.思维导图...

灰度变换与空间滤波

灰度变换与空间滤波 背景知识 空间域指包含图像像素的平面&#xff0c;灰度变换与空间滤波均在空间域进行&#xff0c;即直接在图像像素上操作&#xff0c;表示为 g ( x , y ) T [ f ( x , y ) ] g(x,y)T[f(x,y)] g(x,y)T[f(x,y)] &#xff0c;其中 T T T 是在点 ( x , y…...

敏感接口权限校验

前端校验 &#xff08;从前端或者从token里面拿一下&#xff09;&#xff0c;看一下用户有没有这个页面的权限&#xff08;但是一般不用&#xff0c;因为nodejs也可以写后端&#xff0c;但是放到前端去校验不安全&#xff09; 后端校验 需要梳理敏感数据接口&#xff0c;将这…...

[LeetCode周赛复盘] 第 112场双周赛20230903

[LeetCode周赛复盘] 第 112场双周赛20230903 一、本周周赛总结2839. 判断通过操作能否让字符串相等 I1. 题目描述2. 思路分析3. 代码实现 2840. 判断通过操作能否让字符串相等 II1. 题目描述2. 思路分析3. 代码实现 2841. 几乎唯一子数组的最大和1. 题目描述2. 思路分析3. 代码…...

Spark【RDD编程(二)RDD编程基础】

前言 接上午的那一篇&#xff0c;下午我们学习剩下的RDD编程&#xff0c;RDD操作中的剩下的转换操作和行动操作&#xff0c;最好把剩下的RDD编程都学完。 Spark【RDD编程&#xff08;一&#xff09;RDD编程基础】 RDD 转换操作 6、distinct 对 RDD 集合内部的元素进行去重…...

【2023最新版】MySQL安装教程

目录 一、MySQL简介 二、MySQL安装 1. 官网 2. 下载 3. 安装 4. 配置环境变量 配置前 配置中 配置后 5. 验证 一、MySQL简介 MySQL是一种开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它被广泛用于存储和管理结构化数据。MySQL提供了强大的功…...

关于mysql数据文件损坏导致的mysql无法启动的问题

环境 rocky linux 9 &#xff08;跟centos几乎一模一样&#xff09; myqsl 8.0&#xff0c; 存储引擎使用innodb 问题描述 1. 服务器异常关机&#xff0c;重启启动后发现mysql无法连接&#xff0c;使用命令查看mysql状态&#xff1a; systemctl status mysqld 发现mysql服…...

深度学习之视频分类项目小记

写在前面&#xff0c;最近一阵在做视频分类相关的工作&#xff0c;趁有时间来记录一下。本文更注重项目实战与落地&#xff0c;而非重点探讨多模/视频模型结构的魔改 零、背景 目标&#xff1a;通过多模态内容理解技术&#xff0c;构建视频层级分类体系原技术方案&#xff1a…...

pandas(四十三)Pandas实现复杂Excel的转置合并

一、Pandas实现复杂Excel的转置合并 读取并筛选第一张表 df1 pd.read_excel("第一个表.xlsx") df1# 删除无用列 df1 df1[[股票代码, 高数, 实际2]].copy() df1df1.dtypes股票代码 int64 高数 float64 实际2 int64 dtype: object读取并处理第二张表…...

42、springboot 的 路径匹配 和 内容协商

springboot 的 路径匹配 和 内容协商 对于路径匹配&#xff0c;自己的总结就是&#xff1a; 以前路径匹配时默认不检查后缀&#xff0c;http://localhost:8080/aaa.json 可以直接访问到 RequstMapping(“/aaa”) 的方法。现在不行了。现在会检查后缀了。 内容协商的理解总结&…...

一文讲解Linux内核内存管理架构

内存管理子系统可能是linux内核中最为复杂的一个子系统&#xff0c;其支持的功能需求众多&#xff0c;如页面映射、页面分配、页面回收、页面交换、冷热页面、紧急页面、页面碎片管理、页面缓存、页面统计等&#xff0c;而且对性能也有很高的要求。本文从内存管理硬件架构、地址…...

教你如何使用API接口获取数据

随着互联网技术的发展和应用的普及&#xff0c;越来越多的系统和应用提供API接口供其他系统和应用进行数据交互。通过API接口&#xff0c;我们可以获取到各种各样的数据&#xff0c;例如天气预报、股票行情、新闻摘要等等。本文将介绍如何使用API接口获取数据&#xff0c;并附有…...

集美大学计算机改考408!福建省全面改考,仅剩一个自命题院校

9月5日&#xff0c;集美大学发布通知&#xff0c;0835软件工程、0854电子信息2024考试科目发生变更&#xff01;由822数据结构调整为408计算机学科专业基础 https://zsb.jmu.edu.cn/info/1532/4701.htm 直接由一门改为考四门&#xff0c;难度升级不小。 目前福建省内计算机考…...

Hololens2部署很慢可能是unity工程选择不对

这样就很快&#xff0c;几分钟就完成了。&#xff08;虽然又遇到新问题了&#xff09; 第一次使用时如下&#xff0c;直接运行了一个多小时还没有完...

群论学习记录

群论学习记录 1. 2023.09.07 1. 2023.09.07 群论 (Group Theory) 终极速成 / 物理系零基础火箭级 notes https://zhuanlan.zhihu.com/p/378039151 https://zhuanlan.zhihu.com/p/164653537 群的定义重排定理子群陪集定理&#xff1a;由重排定理可推出1.4-&#xff08;2&#x…...

Fiddler安装与使用教程(2) —— 软测大玩家

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…...

ChatGPT集锦

目录 1. 一条指令让ChatGPT变的更强大2. 对ChatGPT提问时,常见的10种错误描述3. Custom instructions如何设置1. 一条指令让ChatGPT变的更强大 在使用GPT的过程中,如何让AI更清晰地了解你的需求很重要?今天分享一个指令,可以让GPT成为你的好同事,与你一起分析和解决问题,…...

CRM系统中的工作流管理及其重要性

工作流是CRM系统中较为常见的功能&#xff0c;它可以有效减少重复工作、提高销售效率。如果您想深入了解&#xff0c;本文就来详细说说&#xff0c;CRM工作流是什么&#xff1f;工作流的作用&#xff1f; 什么是CRM工作流&#xff1f; CRM工作流是指在CRM系统中&#xff0c;根…...

Go framework-go-zero

一、Go Go天然适配云原生&#xff0c;而云原生时代已经到来&#xff0c;各个应用组件基础设施等都应该积极的去拥抱云原生。 不要让框架束缚开发。 1、go-zero介绍 go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性&#xff0c;…...

【Python】【Fintech】用Python和蒙特卡洛法预测投资组合未来收益

【背景】 想利用蒙特卡洛方法和yahoo,stooq等财经网站上的数据快速预测特定portfolio的收益。 【分析】 整个程序的功能包括 读取json中的portfolio组合创建蒙特卡洛模拟预测收益的算法创建从财经网站获得特定投资组合数据,并根据2的算法获得该Index或Portfolio收益预测结…...

网络层重点协议-IP协议(结构分析)

IP协议数据报格式 一.4位版本号 用来表示IP协议的版本&#xff0c;现有的IP协议只有两个版本IPv4和IPv6 二.4位首部长度 IP协议数据报报头的长度 三.8位服务类型 3位优先权字段&#xff08;已经弃用&#xff09;&#xff0c;4位TOS字段&#xff0c;和1位保留 字段&#xff08;必…...

windows使用vim编辑文本powershell

windows使用vim编辑文本 1、安装 chocolatey 包 以管理员身份打开 PowerShell 进行安装 Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString(https://chocolatey.org/install.ps1))2、管理员身份打开 PowerShell 并使…...

学单片机有前途吗?

学单片机有前途吗? 个人认为学习任何一门技术都比不学的强&#xff0c;针对学单片机有前途吗?那么比较对象当然就是在整个IT行业做对比。因此我们可以从职业前景、钱景、这几方面综合考量。 学单片机有前途吗?我觉得重要的一点就是是否适合职业生涯发展&#xff0c;总说程序…...

【计算机网络】 子网划分

文章目录 IP地址分类子网掩码网关广播地址非默认子网掩码子网划分常见问题 IP地址分类 学会十进制和二进制的相互转换可以很快速的有规律的记住 子网掩码 又叫网络掩码&#xff0c;地址掩码&#xff0c;子网络遮罩&#xff0c;就是说把子网络遮起来&#xff0c;不让外界窥探到…...

vscode ros配置

【ROS】VSCODE ROS 配置方法&#xff08;保姆级教程&#xff0c;总结了多篇&#xff09;_ros vscode_晴明大大的博客-CSDN博客...

【权限提升-Windows提权】-UAC提权之MSF模块和UACME项目-DLL劫持-不带引号服务路径-不安全的服务权限

权限提升基础信息 1、具体有哪些权限需要我们了解掌握的&#xff1f; 后台权限&#xff0c;网站权限&#xff0c;数据库权限&#xff0c;接口权限&#xff0c;系统权限&#xff0c;域控权限等 2、以上常见权限获取方法简要归类说明&#xff1f; 后台权限&#xff1a;SQL注入,数…...

【C++】—— 特殊类设计

目录 序言 &#xff08;一&#xff09;设计一个不能被拷贝的类 &#xff08;二&#xff09;设计一个只能在堆上创建对象的类 &#xff08;三&#xff09;设计一个只能在栈上创建对象的类 &#xff08;四&#xff09;设计一个不能被继承的类 总结 序言 特殊类设计是指在面…...

MFC删除Button控件具体操作

删除Button按键&#xff1b;删除xxxDlg.h中消息映射函数定义 class Ctest4Dlg : public CDialogEx {... public://afx_msg void OnBnClickedButton1();... }删除xxxDlg.cpp中“DoDataExchange”和“BEGIN_MESSAGE_MAP”中的相关代码 void CtestDlg::DoDataExchange(CDataExch…...