TS学习
基本类型
void
void只能接受undeinfed或者作为函数的返回值类型,
let u:void=undefined
function fnVOid():void{} 函数就不能有返回值
void和undefined、null的区别
void值是不可以赋值给其他类型的
let str: string = '123'
let v: void = undefined
~~~str = v~~~ 这样会报错
任意类型
any
any没有强制限定类型,可以对any类型的变量进行任何操作,不需要检查类型。和原生js一样了
常用any的两个地方
①从服务器取得了很复杂的数据(有时间可以一个个定义,没时间直接any)。
type People = {
name: string
age: number
[propName: string]: any //剩余参数类型定义为any
}
let people: People = {
name: 'zds',
age: 12,
score: [1, 2],
}
②引入一些第三方库时,缺失了类型注解
unknow
let unknow: unknown = { a: 123 }
unknow.a 会报错。
unknow比any更安全,不能调用属性和方法,而如果是any类型就不会报错。
对象类型
interface接口
接口实际上是一种约束,给对象的属性定义数据类型约束
//这样写是会报错的 因为我们在person定义了a,b但是对象里面缺少b属性
//使用接口约束的时候不能多一个属性也不能少一个属性
//必须与接口保持一致
interface Person {
b:string,
a:string
}
const person:Person = {
a:"213"
}
但是可以通过可选操作符实现
//可选属性的含义是该属性可以不存在
//所以说这样写也是没问题的
interface Person {
b?:string,
a:string
}
const person:Person = {
a:"213"
}
重名的interface可以合并
//重名的interface可以用于合并
interface A {
name: string
}
interface A {
age: number
}
let x: A = {
name: 'zds',
age: 123
}
任意类型
比如后端返回了一个带有杂七杂八属性的对象,但是前端只需要name和age属性,如何定义数据类型。
只读属性 readonly
interface Mu {
readonly a:string
}
定义对象里的函数类型
需要定义传入的参数类型和返回值类型。接口里定义的是参数类型和返回值类型,而赋值的对象里的函数需要定义传入的参数和返回值,留作调用
interface Axxis {
cb: () => boolean
}
let a: Axxis = {
cb: () => false
}
a.cb = () => true
接口的继承 extends
可以继承多个接口,用 , 分割
interface A {
name: string
}
interface B {
age: number
}
interface C extends A, B {
score: number
}
let c: C = {
name: 'zds',
age: 12,
score: 123
}
给函数定义类型
函数有两种创建方式:①声明式②变量式
声明式函数 定义类型: 一般来说对象里定义方法也都用的该方式
function Fn(name: string): number[] {
return [123]
}
interface obj {
fn: (name: string) => void
}
变量表达式创建的函数 定义类型用接口,但感觉没必要,不如直接定义参数类型和返回值类型。如果该类型需要使用多次,可以用接口方式定义函数类型
interface Fn {
(name: string): number[]
}
const fn: Fn = () => {
return [123]
}
const add: Add = (num1, num2) => {
return num1 + num2
}
const jian = (num1: number, num2: number): number => {
return num1 - num2
}
数组类型
类型[]
//类型加中括号
let arr:number[] = [123]
//这样会报错定义了数字类型出现字符串是不允许的
let arr:number[] = [1,2,3,'1']
//操作方法添加也是不允许的
let arr:number[] = [1,2,3,]
arr.unshift('1')
var arr: number[] = [1, 2, 3]; //数字类型的数组
var arr2: string[] = ["1", "2"]; //字符串类型的数组
var arr3: any[] = [1, "2", true]; //任意类型的数组
数组泛型 但是一般用的比较少,常用的还是类型[]
let arr: Array<number> = [123, 123]
配合interface定义对象数组 type也是可以的,但是type用的很少
interface X {
name: string
age: number
}
let arr: X[] = [{ name: '小曼', age: 12 }]
定义二维数组
方式① let arr: number[][] = [[1], [2]]
方式② 用的不多
大杂烩数组 let arr: any[] = [1, 'absd', false] 也可以用元组,即一一枚举,但是很麻烦
let num: [number, string, boolean] = [1, 'a', false]
在函数中使用 在函数剩余参数中使用
function Fn(...ages: number[]) {
console.log(ages)
}
Fn(1, 2, 3)
给函数的arguments定义类型 ts内部提供了IArguments
函数扩展
定义函数类型的两种方式 声明式和变量表达式
function Fn(name: string): number[] {
return [123]
}
interface obj {
fn: (name: string) => void
}
变量表达式创建的函数 定义类型用接口
当然也可以写全,但是写全不就浪费时间麻烦了吗
interface Fn {
(name: string): number[]
}
const fn: Fn = () => {
return [123]
}
interface Add {
(num1: number, num2: number): number
}
const add: Add = (num1, num2) => {
return num1 + num2
}
函数的形参可选参数 不传是undefined
//通过?表示该参数为可选参数
const fn = (name: string, age?:number): string => {
return name + age
}
fn('张三')
函数参数默认值
const fn = (name: string = "我是默认值"): string => {
return name
}
fn()
函数重载
function fn(params: number): void
function fn(params: string, params2: number): void
//上两个是重载函数,下面这个是执行函数,因为多了个params2,所以必须是可选,执行函数参数类型必须是any
function fn(params: any, params2?: any): void {
console.log(params)
console.log(params2)
}
fn(123)
fn('123',456)
联合类型 |
其实就是或 同时支持多个类型
let num: number | string = 1
let fn = function (type: number | boolean): boolean {
return !!type
}
console.log(!!null);
交叉类型 &
其实就是and,就是必须同时满足两个类型
interface A {
name: string
}
interface B {
age: number
}
let C: A & B = {
name: '123',
age: 12
}
类型断言
语法: 值 as 类型 或者 <类型>值
需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误: 常用第一种: value as string
解决办法:
let fn = function (num: number | string): void {
//断言它是string类型,即使是number类型也不会报错,但是运行后是undefined
console.log((num as string).length)
}
fn(123)
TS内置对象
Boolean、Number、string、RegExp、Date、Error
let b: Boolean = new Boolean(1)
console.log(b)
let n: Number = new Number(true)
console.log(n)
let s: String = new String('哔哩哔哩')
console.log(s)
let d: Date = new Date()
console.log(d)
let r: RegExp = /^1/
console.log(r)
let e: Error = new Error("error!")
console.log(e)
DOM和BOM的内置对象
Document、HTMLElement、Event、NodeList等
常用的几个类型HTMLElement、MouseEvent、NodeList
let body: HTMLElement = document.body;
//读取所有节点 querySelectorAll()===>NodeList
let allDiv: NodeList = document.querySelectorAll('div');
//单独读取某一个元素 这种需要类型断言(是什么元素) 或者加个判断应为读不到返回null
let div:HTMLElement = document.querySelector('div')as HTMLDivElement
document.addEventListener('click', function (e: MouseEvent) {
});
Proimse
//返回Promise
function myPromise(): Promise<number> {
return new Promise<number>((resolve, reject) => {
resolve(1)
})
}
myPromise().then(res => {
console.log(res)
})
//dom元素的映射表
interface HTMLElementTagNameMap {
"a": HTMLAnchorElement;
"abbr": HTMLElement;
"address": HTMLElement;
"applet": HTMLAppletElement;
"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": HTMLTableDataCellElement;
"template": HTMLTemplateElement;
"textarea": HTMLTextAreaElement;
"tfoot": HTMLTableSectionElement;
"th": HTMLTableHeaderCellElement;
"thead": HTMLTableSectionElement;
"time": HTMLTimeElement;
"title": HTMLTitleElement;
"tr": HTMLTableRowElement;
"track": HTMLTrackElement;
"u": HTMLElement;
"ul": HTMLUListElement;
"var": HTMLElement;
"video": HTMLVideoElement;
"wbr": HTMLElement;
}
class类
类的定义
必须提前声明属性和方法的类型
所以可以直接赋初始值,或者是调用
类修饰符
public:可以在外部通过变量直接调用,也可以在定义类的构造器或者方法里(即类内部)调用
private:只可以在当前类的内部调用
protect:可以在类内部和子类中访问
static 静态属性和方法 静态属性不可以通过this去调用,只能通过类名访问
静态函数不能访问其他变量,只能访问静态变量。类里面也不能通过this.静态方法调用,只能类名.静态方法
需要注意的是:两个静态方法可以相互通过this掉用,但也可以通过类名
抽象类
我们B类实现了A定义的抽象方法 如不实现就不报错 我们定义的抽象方法必须在派生类实现
元组
元组就是数组的变种,js中数组可以存放任意数据类型的数据,ts中数组只能存放特定类型的数据。因此如果想要存放不同类型的数据到数组里,就创造了元组 let arr: [number, string] = [12, '112']
它会被推断成一个联合类型
 {
switch (val.type) {
case 'foo':
break;
case 'bar':
break
default:
//兜底逻辑 一般是不会进入这儿如果进来了就是程序异常了
const exhaustiveCheck:never = val;
break
}
Symbol
symbol类型的值是通过Symbol构造函数创建的 只支持传入number和string for in是不会循环symbol类型的属性
迭代器函数:通过next.done是否为false判断是否结束,如果为true,则结束循环
//迭代器函数 这其实就是for of的原理
let set: Set<number> = new Set([1, 2, 3, 4, 5])
type MapKeys = string | number
let map: Map<MapKeys, MapKeys> = new Map()
map.set('1', '网页')
map.set('2', '往上')
function generation(erg: any) {
let it: Iterator<any> = erg[Symbol.iterator]()
let next: any = { done: false }
while (!next.done) {
//如果next中没结束,就一直循环
next = it.next()
if (!next.done) {
console.log(next)
}
}
}
generation(map)
for of 和for in区别
for in 循环数组,i输出的是索引,for of 是输出的值 遍历对象的时候 for in 是属性 of是value
泛型
语法:函数名字后面<参数名>,当使用这个函数的时候把参数的类型传递进去即可
定义时,不明确类型,使用时再确定唯一的类型
function add<T>(num1: T, num2: T): T[] {
return [num1, num2]
}
//在使用时,必须明确类型
add<number>(1, 2)
定义了多个类型的泛型
function sub<T, U>(a: T, b: U): Array<T | U> {
return [a, b]
}
sub<number, boolean>(1, false)
sub(2, '3')
泛型约束
解决办法:①通过类型断言 as
function getLength<T>(arg: T) {
return (arg as string).length
}
console.log(getLength(1))
②定义泛型约束
即定义了一个接口,里面还有属性,让泛型来继承,这样传递的参数必须要有length属性才能传递
keyof 约束对象,这样如果返回对象没有的键值对就会报错
泛型类
//泛型类
class Sub<T> {
attr: T[] = []
constructor(num: T[]) {
this.attr = num
}
public add(a: T): T[] {
return [a]
}
}
let s = new Sub<number>([1, 2, 3])
console.log(s.attr)
tsconfig.json 配置文件
include: 指定编译文件默认是编译当前目录下所有的ts文件
exclude: 排除某个文件,对某个文件不进行编译
target: js编译的版本 可以选择es2015 或者2016
outDir: 编译后文件输出目录
rootDir: 编译文件的目录
namespace 命名空间
ts和es2015一样,任何包含import或者export都被当成一个模块,相反的是,如果没有import和export 那么他的内容就被视为全局的。
解决办法:生成局部作用域
①匿名函数②export 导出即可③namespace
其实它的原理就是用了匿名立即执行函数
三斜线指令
声明文件
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
问题:
解决办法: 1、npm i --save-dev @types/express 但是只有热门库才会有声明文件
2、自己定义 express.d.ts
装饰器 Decorator
必须在tsconfig.json中开启
类装饰器:就是将类的构造函数传入到watch参数
const watcher: ClassDecorator = (target: Function) => {
target.prototype.getName = <T>(name: T): T => {
return name
}
}
@watcher
class A {
constructor() {}
}
let a = new A()
console.log((a as any).getName('123124'))
装饰器工厂
//说白了就是外面再套一层函数,用高阶函数的方式传递参数
const watcher = (name: string): ClassDecorator => {
return (target: Function) => {
target.prototype.getParams = () => {
return name
}
}
}
@watcher('zds')
class A {}
const a = new A()
console.log((a as any).getParams('123'))