说明
工作在TS的严格模式下
基础类型
string
let str:string = 'ts'
let str1:string = `${str}1`
number
let notNumber:number = NaN // 非数字
let infinityNumber:number = Infinity // 无穷大
let binary:number = 0b1010 // 二进制
let octal: number = 0o744;//八进制
let num:number = 123 // 十进制
let hex:number = 0xf00d // 十六进制
boolean
注意通过new出来的是对象
let createdBoolean: Boolean = new Boolean(1)
Boolean != boolean
let booleand: boolean = true //可以直接使用布尔值
let booleand2: boolean = Boolean(1) //也可以通过函数返回布尔值
null
let n: null = null;//定义null
undefined
let u: undefined = undefined;//定义undefined
void
JavaScript 没有空值(Void)的概念
在 TypeScript 中,可以用 void
表示没有任何返回值的函数
function voidFn(): void {
console.log('test void')
}
void可以接收undefined
let u: void = undefined
任意类型
any
对any类型进行赋值不进行类型检查,any类型赋值给其它变量(与值类型相同)依然要进行类型检查
声明变量的时候没有指定任意类型默认为any
any可以进行.操作
let anys;
anys = '123'
anys = true
let anys:any = 123
anys = '123'
anys = true
unknown
对unknown类型进行赋值不进行类型检查,unknown只能赋值给any和unknown的变量,不管其值是什么
unknown不能进行.操作
接口
在给接口赋值时,通过花括号完成
interface
interface Person {
b:string,
a:string
}
const person:Person = {
a:"213"
}
// 会报错默认情况下interface定义的属性必须全部包含
接口函数
TS可以抽象函数,这应该是java没有的
interface Func{
(x:number):number // 注意,接口在抽象函数时的写法,与函数的两种类型定义方式都不一致
}
let f:Func = function(x1:number):number{
console.log(x1)
return 0
}
合并
重名的interface会在程序执行前合并
interface A{name:string}
let x:A={name:'xx',age:20}
interface A{age:number} // 注意,虽然看似age:number实例化后执行,但是合并先于实例化
继承
interface B extends A{
age:number
}
可选属性
interface Person {
b?:string,
a:string
}
const person:Person = {
a:"213"
}
任意属性
interface Person {
b?:string,
a:string,
[propName: string]: any;
}
const person:Person = {
a:"213",
c:"123"
}
只读属性
readonly 只读属性是不允许被赋值的只能读取
//这样写是会报错的
//因为a是只读的不允许重新赋值
interface Person {
b?: string,
readonly a: string,
[propName: string]: any;
}
const person: Person = {
a: "213",
c: "123"
}
person.a = 123
添加函数
interface Person {
b?: string,
readonly a: string,
[propName: string]: any;
cb():void
}
const person: Person = {
a: "213",
c: "123",
cb:()=>{
console.log(123)
}
}
类
TS和类和java类差不多,但不支持方法重载
class Person {
public name:string
private age:number
protected some:any
constructor (name:string,ages:number,some:any) {
this.name = name
this.age = ages
this.some = some
}
run () {
}
}
权限修饰符
public
内部访问 也可以外部访问 如果不写默认就是public
private
只能在内部访问 不能在外部访问
protected
只能在内部和继承的子类中访问 不能在外部访问
statice
与java相同
实现接口
interface PersonClass {
get(type: boolean): boolean
}
interface PersonClass2 {
set(): void,
asd: string
}
class A {
name: string
constructor() {
this.name = "123"
}
}
class Person extends A implements PersonClass, PersonClass2 {
asd: string
constructor() {
super()
this.asd = '123'
}
get(type: boolean) {
return type
}
set() {
}
}
继承
class Person {
public name: string
private age: number
protected some: any
constructor(name: string, ages: number, some: any) {
this.name = name
this.age = ages
this.some = some
}
run() {
}
}
class Man extends Person {
constructor() {
super("张三", 18, 1)
console.log(this.some)
}
create() {
console.log(this.some)
}
}
let xiaoman = new Person('小满', 18, 1)
let man = new Man()
man.some
抽象类
abstract class A {
name: string
constructor(name: string) {
this.name = name;
}
print(): string {
return this.name
}
abstract getName(): string
}
class B extends A {
constructor() {
super('小满')
}
getName(): string {
return this.name
}
}
let b = new B();
console.log(b.getName());
数组类型
定义
括号方式
let arr:number[] = [1,2,3,4,5]
泛型方式
let arr:Array<number> = [1,2,3,4,5]
多维数组
括号方式
let arr:number[][] = [[1,2,3,4,5]]
泛型方式
let arr:Array<Array<Number>> = [[1,2,3,4,5]]
arguments类数组
function Arr(...args:any): void {
let arr:IArguments = arguments // ts内置IArguments接口,用于定义参数数组变量
}
Arr(111, 222, 333)
interface IArguments {
[index: number]: any;
length: number;
callee: Function;
}
元组类型
元组就是数组的变种,元组(tuple)是固定数量的不同类型的元素的组合
let arr:[number,string] = [1,'string'] // 类型数量位置必须一一对应
let arr2: readonly [number,boolean,string,undefined] = [1,true,'sring',undefined] // 类型数量位置必须一一对应
越界元素
依然元组的本意是固定数量类型不同,但因为元组是数组的变种,依然是使用数组实现的,所以在正确赋值后可以使用push添加元素,但是该元素只能是元组定义类型的联合类型
函数类型
函数不声明返回值的话执行完毕默认返回void
分类
箭头函数方式
let func:(x:number)=>void // 箭头函数方式,该方式可以同时约束返回值和参数
Function方式
let func:Function // Function方式,该方式不能约束返回值和参数
函数变量
let fn:Function // 可以将其它函数赋值给fn, 注意F时大写
函数常量
通过function标识符方式定义的函数常量,不能再将函数赋值给该标识符
function fn(){}
函数扩展
参数数量相同
const fn = (name: string, age:number): string => {
return name + age
}
fn('张三') // 报错,参数数量必须和定义时保持一致
可选参数
const fn:Function = (name: string, age?:number): string => {
return name + age // age的值为undefined
}
fn('张三')
默认值
const fn = (name: string = "我是默认值"): string => {
return name
}
fn()
函数重载
定义:重载是函数名字相同,而参数不同,返回类型可以相同也可以不同
TS函数重载与java方法不同,TS函数重载指的是函数签名的重载,不能对函数体进行重载,执行的是相同的函数体
参数类型重载
实现签名函数的对应参数类型应设置为any
function fn(a:number):void // 重载签名,没有函数体,因为不能对函数体重载
function fn(a:any):number{ // 因为有函数体,所以该函数是实现签名,并且要重载的参数类型为any
console.log(456)
return 0
}
参数数量重载
实现签名函数的对应参数修饰符应设置为可选(?)
function fn(a:number):void // 重载签名,没有函数体,因为不能对函数体重载
function fn(a?:number):number{ // 因为有函数体,所以该函数是实现签名,并且要重载的参数修饰符为可选(?)
console.log(456)
return 0
}
泛型
泛型函数
function Sub<T,U>(a:T,b:U):Array<T|U> {
const params:Array<T|U> = [a,b]
return params
}
Sub<Boolean,number>(false,1)
Sub(false,1) // 支持泛型简写
泛型接口
interface MyInter<T> {
(arg: T): T // TS接口可以直接约束函数,注意接口抽象函数时的写法,与函数的两种类型定义方式都不一致
}
function fn<T>(arg: T): T {
return arg
}
let result: MyInter<number> = fn
result(123)
泛型类
class Sub<T>{
attr: T[] = [];
add (a:T):T[] {
return [a]
}
}
let s = new Sub<number>()
s.attr = [1,2,3]
s.add(123)
let str = new Sub<string>()
str.attr = ['1','2','3']
str.add('123')
泛型约束
类型约束
interface Len {
length:number
}
function getLegnth<T extends Len>(arg:T) { // 泛型T上必须拥有length属性并且类型为number
return arg.length
}
getLegnth<string>('123')
值约束
function prop<T, K extends keyof T>(obj: T, key: K) { // keyof将对象的自定义属性名变换成联合类型
return obj[key]
}
let o = { a: 1, b: 2, c: 3 }
prop(o, 'a')
prop(o, 'd') //此时就会报错发现找不到
联合类型
let num_str: number | string // 表示变量可以接收number数据也可以接收string数据,应当注意的是联合类型会导致类型不确定,所以默认只能使用相同的方法和属性。
// 结合类型断言就可以使用独有的方法
num_str = '010-820'
num_str = 0
联合值
let nm:1|2|4 = 1 // |不仅有限定联合类型,还有联合值的作用
交叉类型
多种类型的集合,联合对象将具有所联合类型的所有成员
interface A{
num:number
}
interface B{
str:string
}
let t: A & B = { // 如果存在相同的属性B会覆盖A的属性,类推
num:123,
str:"456"
}
枚举类型
使用enum关键字定义枚举
enum Types { // 默认情况下第一个元素为0,如果第n+1号元素没有指定值,那么n+1号元素值为n号元素的值+1(如果n号元素不是数字的话,n+1号元素必须指定值)
Red,
Green = 4,
BLue
}
console.log(Types.Red) // 0
console.log(Types.Green) // 4
console.log(Types.BLue) // 5
const枚举
枚举元素值只能是number和string
let 和 var 都是不允许的声明只能使用const,const声明和普通声明它们的区别是编译后js文件的区别
const enum Types{ // const声明
No = "No",
Yes = 1,
}
console.log(Types.No)
console.log("No" /* Types.No */); // const在编译后,直接将对应的值编译到对应的位置
enum Types{ // 普通声明
No = "No",
Yes = 1,
}
console.log(Types.No)
var Types;
(function (Types) {
Types["No"] = "No";
Types[Types["Yes"] = 1] = "Yes";
})(Types || (Types = {}));
console.log(Types.No); // 直接通过立即执行函数编译成对象
反向映射
通过const枚举案例可知,当普通声明并且值为number时,使用键和值进行了交替使用赋值。所以满足上述条件可以通过值拿到键。
enum Types{
No = "No",
Yes = 1,
}
console.log(Types[1]) // Yes
never
never 类型用来表示不应该存在的状态,而void表示没有
type sn = string & number // sn会被推论成never类型,因为string和number交叉类型不存在
function go():never{ // 函数一直执行,所以不存在返回值
while(true){
}
}
function go():never{ // 函数报错,所以不存在返回值
throw new Error
}
Symbol
与js相同,只有通过以下三种方法可以获取Symbol属性对应的数据
const symbol1 = Symbol('666')
const symbol2 = Symbol('777')
const obj1= {
[symbol1]: '小满',
[symbol2]: '二蛋',
age: 19,
sex: '女'
}
console.log(obj1[symbol1]) // 方法1,持有Symbol对象
console.log(obj1[Reflect.ownKeys(obj1)[3]]) // 方法2,通过Reflect.ownKeys(obj1)将定义的属性转数组,再通过方法1获取
console.log(obj1[Object.getOwnPropertySymbols(obj1)[0]]) //方法3,通过Object.getOwnPropertySymbols(obj1)将定义的--Symbol--属性转数组,再通过方法1获取
标准内置对象
DOM 和 BOM 的内置对象
document.body
let body: HTMLElement = document.body;
console.log(body)
document.querySelectorAll
let allDiv: NodeList = document.querySelectorAll('div');
document.getElementById
let node:Node | null = document.getElementById("i")
console.log(node)
dom元素的映射表
interface HTMLElementTagNameMap {
"a": HTMLAnchorElement;
"abbr": HTMLElement;
"address": HTMLElement;
"area": HTMLAreaElement;
"article": HTMLElement;
"aside": HTMLElement;
"audio": HTMLAudioElement;
"b": HTMLElement;
"base": HTMLBaseElement;
"bdi": HTMLElement;
"bdo": HTMLElement;
"blockquote": HTMLQuoteElement;
"body": HTMLBodyElement;
"br": HTMLBRElement;
"button": HTMLButtonElement;
"canvas": HTMLCanvasElement;
"caption": HTMLTableCaptionElement;
"cite": HTMLElement;
"code": HTMLElement;
"col": HTMLTableColElement;
"colgroup": HTMLTableColElement;
"data": HTMLDataElement;
"datalist": HTMLDataListElement;
"dd": HTMLElement;
"del": HTMLModElement;
"details": HTMLDetailsElement;
"dfn": HTMLElement;
"dialog": HTMLDialogElement;
"dir": HTMLDirectoryElement;
"div": HTMLDivElement;
"dl": HTMLDListElement;
"dt": HTMLElement;
"em": HTMLElement;
"embed": HTMLEmbedElement;
"fieldset": HTMLFieldSetElement;
"figcaption": HTMLElement;
"figure": HTMLElement;
"font": HTMLFontElement;
"footer": HTMLElement;
"form": HTMLFormElement;
"frame": HTMLFrameElement;
"frameset": HTMLFrameSetElement;
"h1": HTMLHeadingElement;
"h2": HTMLHeadingElement;
"h3": HTMLHeadingElement;
"h4": HTMLHeadingElement;
"h5": HTMLHeadingElement;
"h6": HTMLHeadingElement;
"head": HTMLHeadElement;
"header": HTMLElement;
"hgroup": HTMLElement;
"hr": HTMLHRElement;
"html": HTMLHtmlElement;
"i": HTMLElement;
"iframe": HTMLIFrameElement;
"img": HTMLImageElement;
"input": HTMLInputElement;
"ins": HTMLModElement;
"kbd": HTMLElement;
"label": HTMLLabelElement;
"legend": HTMLLegendElement;
"li": HTMLLIElement;
"link": HTMLLinkElement;
"main": HTMLElement;
"map": HTMLMapElement;
"mark": HTMLElement;
"marquee": HTMLMarqueeElement;
"menu": HTMLMenuElement;
"meta": HTMLMetaElement;
"meter": HTMLMeterElement;
"nav": HTMLElement;
"noscript": HTMLElement;
"object": HTMLObjectElement;
"ol": HTMLOListElement;
"optgroup": HTMLOptGroupElement;
"option": HTMLOptionElement;
"output": HTMLOutputElement;
"p": HTMLParagraphElement;
"param": HTMLParamElement;
"picture": HTMLPictureElement;
"pre": HTMLPreElement;
"progress": HTMLProgressElement;
"q": HTMLQuoteElement;
"rp": HTMLElement;
"rt": HTMLElement;
"ruby": HTMLElement;
"s": HTMLElement;
"samp": HTMLElement;
"script": HTMLScriptElement;
"section": HTMLElement;
"select": HTMLSelectElement;
"slot": HTMLSlotElement;
"small": HTMLElement;
"source": HTMLSourceElement;
"span": HTMLSpanElement;
"strong": HTMLElement;
"style": HTMLStyleElement;
"sub": HTMLElement;
"summary": HTMLElement;
"sup": HTMLElement;
"table": HTMLTableElement;
"tbody": HTMLTableSectionElement;
"td": HTMLTableCellElement;
"template": HTMLTemplateElement;
"textarea": HTMLTextAreaElement;
"tfoot": HTMLTableSectionElement;
"th": HTMLTableCellElement;
"thead": HTMLTableSectionElement;
"time": HTMLTimeElement;
"title": HTMLTitleElement;
"tr": HTMLTableRowElement;
"track": HTMLTrackElement;
"u": HTMLElement;
"ul": HTMLUListElement;
"var": HTMLElement;
"video": HTMLVideoElement;
"wbr": HTMLElement;
}
接收Promise
let pm:Promise<number> = new Promise<number>((resolve,reject)=>{
resolve(1)
})
类型断言
需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误
编译过程中会删除类型断言
as方式
(变量 as 类型)
let fn = function(num:string | number):void{
console.log((num as string).length)
}
fn("123")
泛型方式
(<类型>变量)
let fn = function(num:string | number):void{
console.log((<string>num).length)
}
fn("123")
类型推论
let str = "123" // 声明变量并赋初值,str被推论成string
let char // 声明变量未赋初值,char被推论成any
类型别名
变量
type XX = string | boolean | 1
let x:XX = 1 // 注意,类型别名不仅是类型取别名,还有限制取值的功能
函数
不约束返回值
type func = Function // Function关键字无法约束函数的返回值
let f:func = ()=>123
约束返回值
type func = ()=>string // 箭头函数可以约束函数的返回值
let f:func = function():string{
return "123"
}
变量操作符
可选
只能用于接口属性定义和函数参数声明时使用
属性
interface Person {
b?:string,
a:string
}
const person:Person = {
a:"213"
}
参数
const fn:Function = (name: string, age?:number): string => {
return name + age // age的值为undefined
}
fn('张三')
tsconfig.json配置文件
"compilerOptions": {
"incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
"tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
"diagnostics": true, // 打印诊断信息
"target": "ES5", // 目标语言的版本
"module": "CommonJS", // 生成代码的模板标准
"outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
"lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
"allowJS": true, // 允许编译器编译JS,JSX文件
"checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用
"outDir": "./dist", // 指定输出目录
"rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
"declaration": true, // 生成声明文件,开启后会自动生成声明文件
"declarationDir": "./file", // 指定生成声明文件存放目录
"emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
"sourceMap": true, // 生成目标文件的sourceMap文件
"inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中
"declarationMap": true, // 为声明文件生成sourceMap
"typeRoots": [], // 声明文件目录,默认时node_modules/@types
"types": [], // 加载的声明文件包
"removeComments":true, // 删除注释
"noEmit": true, // 不输出文件,即编译后不会生成任何js文件
"noEmitOnError": true, // 发送错误时不输出任何文件
"noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
"importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
"downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
"strict": true, // 开启所有严格的类型检查
"alwaysStrict": true, // 在代码中注入'use strict'
"noImplicitAny": true, // 不允许隐式的any类型
"strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
"strictFunctionTypes": true, // 不允许函数参数双向协变
"strictPropertyInitialization": true, // 类的实例属性必须初始化
"strictBindCallApply": true, // 严格的bind/call/apply检查
"noImplicitThis": true, // 不允许this有隐式的any类型
"noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
"noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错)
"noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
"noImplicitReturns": true, //每个分支都会有返回值
"esModuleInterop": true, // 允许export=导出,由import from 导入
"allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块
"moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
"paths": { // 路径映射,相对于baseUrl
// 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置
"jquery": ["node_modules/jquery/dist/jquery.min.js"]
},
"rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错
"listEmittedFiles": true, // 打印输出文件
"listFiles": true// 打印编译的文件(包括引用的声明文件)
}
// 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
"include": [
"src/**/*"
],
// 指定一个排除列表(include的反向操作)
"exclude": [
"demo.ts"
],
// 指定哪些文件使用该配置(属于手动一个个指定文件)
"files": [
"demo.ts"
]
namespace命名空间
TypeScript与ECMAScript 2015一样,任何包含顶级import
或者export
的文件都被当成一个模块。相反地,如果一个文件不带有顶级的import
或者export
声明,那么它的内容被视为全局可见的(仅仅是全局智能提示可见)
namespace其实是将空间名作为对象,要导出的变量名做属性,变量值做对应的值
namespace a {
export const Time: number = 1000 // 命名空间中通过export将想要暴露的部分导出,
export const fn = <T>(arg: T): T => {
return arg
}
fn(Time)
}
a.Time
let nm = 0 // 注意,nm依然是全局可见,如果export namespace a那么nm将不可见,不满足条件
编译后
"use strict";
exports.__esModule = true;
exports.a = void 0;
var a;
(function (a) {
a.Time = 1000; // 命名空间中通过export将想要暴露的部分导出,
a.fn = function (arg) {
return arg;
};
a.fn(a.Time);
})(a = exports.a || (exports.a = {}));
a.Time;
var nm = 0; // 注意,nm依然是全局可见
嵌套
namespace a {
export namespace b { // 注意,在进行命名空间嵌套时,子命名空间也要使用export导出
export class Vue {
parameters: string
constructor(parameters: string) {
this.parameters = parameters
}
}
}
}
let v = a.b.Vue
new v('1')
抽离
export namespace V { // 将命名空间对象通过export导出
export const a = 1
}
简化
namespace A {
export namespace B {
export const C = 1
}
}
import X = A.B.C // 注意,ts-node不支持
console.log(X);
合并
namespace a{
export let s = 0 // 注意命名空间名可以重复,但要导出的量,不能重复
}
namespace a{
export let ss = 6
}
三斜线指令
三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。
三斜线指令仅可放在包含它的文件的最顶端。 一个三斜线指令的前面只能出现单行或多行注释,这包括其它的三斜线指令。 如果它们出现在一个语句或声明之后,那么它们会被当做普通的单行注释,并且不具有特殊的涵义。
它用于声明文件间的依赖。
a.ts
namespace A {
export const fn = () => 'a'
}
b.ts
namespace A {
export const fn2 = () => 'b'
}
index.ts
///<reference path="./a.ts" />
///<reference path="./b.ts" />
console.log(A);
declare
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能
declare var 声明全局变量 declare function 声明全局方法 declare class 声明全局类 declare enum 声明全局枚举类型 declare namespace 声明(含有子属性的)全局对象 interface 和 type 声明全局类型 /// 三斜线指令
Partial
将属性全部转换为可选属性
type Person = {
name:string,
age:number
}
type p = Partial<Person>
// 得到
type p = {
name?: string | undefined;
age?: number | undefined;
}
Pick
选取指定属性并返回
type Person = {
name:string,
age:number,
text:string
address:string
}
type Ex = "text" | "age"
type A = Pick<Person,Ex>
Readonly
给所有属性添加readonly只读
Record
type k = "A" | "B"
type Person = {
name:string
age:number
}
type B = Record<k,Person> // type B拥有A和B属性,并且类型为Person
infer
在extends语句中,支持infer关键字,可以推断一个类型变量,高效的对类型进行模式匹配。但是,这个类型变量只能在true的分支中使用。类型的占位符
// 如果泛型T是()=> infer R的子集,则返回infer R获取到的类型,否则返回boolean
type Func<T> = T extends () => infer R ? R : boolean;
let func1: Func<number>; // boolean;
let func2: Func<''>; // boolean
let func3: Func<() => Promise<number>>; // Promise<number>