TypeScript
视频
黑马2020年前端热门教程推荐|五天从零基础学会TypeScript
TypeScript从入门到精通视频教程-2020年新版
个人认为先学第一个视频在学第二个
欢迎补充~
安装与运行
正常版
简化版
初体验
注释
单行注释
// content
多行注释
/* content */
输出语句
console.log(' content ')
变量和数据类型
什么是变量
变量是用来存储数据的容器,并且是可以变化的。
变量的使用
let age: number = 20
age = 21
console.log(age)
类型注解
类型注解是为变量添加类型约束的方式
约定了什么类型,只能给变量赋值什么类型的值。
静态数据类型
基础静态类型:number string null undefined boolean
对象静态类型:对象类型 数组类型 类类型 函数类型
null undefined
undefined 声明但未赋值的值
null 声明并且赋值,赋的值未null。
运算符
算术运算符
( + - * / )
+可实现字符串拼接
赋值运算符
= | += | -= | /= | *=
递增/递减运算符
++ | - -
比较运算符
逻辑运算符
&& ||
循环
for(let i: number = 0; i < 3; i++) {
console.log(i)
}
数组
// 此数组只能存储字符串
let names: string[] = ['lyz', 'my']
console.log(names)
let per : (string|number)[] = ['lyz','my', 21]
// 类型别名
type Lady = {name: string, age: number}
let arr : Lady[] = [
{name: 'lyz', age: 21},
{name: 'my', age: 22}
]
元组
不常用
let arr : [string, number, string] = ['lyz', 21,'lyz']
函数
function sing(songName: string) {
console.log(songName)
}
sing('有点甜')
// 函数返回值
function sum(number1: number, number2: number):number {
return number1 + number2
}
let total = sum(1, 2)
console.log(total)
// 参数为对象
function obj({one} : {one: number}) {
return one
}
console.log(obj({one: 99}))
对象
类型注解
let person: {
name: string;
age: number;
sayHi: () => void;
}
person = {
name: 'lyz',
age: 21,
sayHi() {
console.log('hi')
}
}
接口
为对象的类型注解命名,并为你的代码建立契约来约束对象的结构
// height可有可无 any任意类型
let person: {
name: string;
age: number;
height ?: number;
[propname: string] : any;
sayHi: () => void;
}
person = {
name: 'lyz',
age: 21,
sex: 'nv',
sayHi() {
console.log('hi')
}
}
console.log(p.sayHi(1))
interface Girl {
name: string
}
let g = {
name: 'lyz'
}
function say(g : Girl) {
console.log(g.name)
}
say(g)
继承
interface IUser {
name: string;
age: number;
sayHi: (number) => number;
}
interface Teacher extends IUser {
teach: () => void
}
let te = {
name: 'lyz',
age: 21,
sayHi(num) {
return num
},
teach() {
console.log('I am teacher')
}
}
console.log(te.sayHi(99))
te.teach()
类型推论
在TS中,某些没有明确指出类型的地方,类型推论会帮助提供类型
发生类型推论的两种场景:1. 什么变量并初始化;2. 决定函数返回值时。
类
class Person {
content = 'hello'
sayHi() {
return 'hi'
}
}
class Girl extends Person {
sayHi() {
return super.sayHi() + ' world'
}
dance() {
console.log('i can dance')
}
}
const g = new Girl()
console.log(g.sayHi())
g.dance()
访问类型
public 类的内部和类的外部都能使用
protected 类的内部使用(继承中可使用)
private 只能在类的内部使用(继承中也不可能)
构造函数
class Person {
public name: string
constructor(name: string) {
this.name = name
}
}
继承中必须写super()
//简化
class Person {
constructor(public name: string) {}
}
class Teacher extends Person {
constructor(public age: number) {
super('lyz')
}
}
const per = new Teacher(21);
console.log(per.name)
console.log(per.age)
class Person {
constructor(public name: string) {}
}
class Teacher extends Person {
constructor(public name: string, public age: number) {
super(name)
}
}
const per = new Teacher('lyz', 21);
console.log(per.name)
console.log(per.age)
Getter Setter static
class Girl {
constructor(private _age: number) {}
get age() {
return this._age-10
}
set age(age: number) {
this._age = age + 7
}
}
let girl = new Girl(21)
console.log(girl.age) // 11 返回的值为getter中的值
girl.age = 22 // 设置的是setter中 此时age为29 [22+7]
console.log(girl.age) // 19 [29-10]
静态类
无需实例化对象,就可以直接调用类中的方法。
class Person {
static sayHi() {
console.log('hi')
}
}
Person.sayHi()
只读属性
class Girl {
public readonly _name: string
constructor(name: string) {
this._name = name
}
}
let girl = new Girl('lyz')
// girl._name = 'my' 不可对_name进行修改
console.log(girl._name)
抽象类
必须要重写抽象方法 否则会报错
abstract class Person {
abstract say()
}
class Girl extends Person {
say() {
console.log('say boy')
}
}
class Boy extends Person {
say() {
console.log('say girl')
}
}
tsconfig.json文件
//tscongif起作用
tsc
联合类型和类型守护
interface Student {
doing: false
say: () => void
}
interface Teacher {
doing: true
take: () => void
}
function who(per: (Student | Teacher)) {
if(per.doing) {
(per as Teacher).take()
} else {
(per as Student).say()
}
}
who({doing: true, take(){console.log('take')}})
interface Student {
doing: false
say: () => void
}
interface Teacher {
doing: true
take: () => void
}
function who(per: (Student | Teacher)) {
if('say' in per) {
per.say()
} else {
per.take()
}
}
who({doing: false, say(){console.log('say')}})
function add(first: (string | number), second: (string | number)) {
if(typeof first === 'string' || typeof second === 'string') {
return `${first}${second}`
}
return first +second
}
console.log(add('9', 9))
console.log(add(9, 9))
class NumObj {
constructor(public count: number){}
}
function add(first: NumObj | object, second: NumObj | object) {
if(first instanceof NumObj && second instanceof NumObj) {
return first.count + second.count
}
return 0
}
let first = new NumObj(1)
let second = new NumObj(1)
console.log(add(first,second))
枚举
enum Dream {
House,
White,
Beauty
}
function getDream(dream: any) {
if(dream === Dream.White) {
console.log("White")
} else if (dream === Dream.House) {
console.log("House")
} else if (dream === Dream.Beauty) {
console.log("Beauty")
}
}
getDream(1)
console.log(Dream.White, Dream[1]) //1 'White'
console.log(Dream.House) // 0
console.log(Dream.Beauty) // 2
泛型
在函数调用时确定类型
函数
function add<T>(first: T, second: T) {
return `${first}${second}`
}
console.log(add<string>('m', 'y'))
function getArr<T>(arr: Array<T>){
return arr
}
console.log(getArr<number>([1, 2]))
function getArray<T>(arr: T[]){
return arr
}
console.log(getArray<string>(['9', '9']))
function add<T, P>(first: T, second: P) {
return `${first}${second}`
}
console.log(add<string, number>('m', 1))
类
class SelectGirls<T> {
constructor(public girl: T[]) {}
getGirl(index: number) {console.log(this.girl[index])}
}
let g = new SelectGirls(['lyz', 'glnz', 5])
g.getGirl(2)
继承
interface Girl {
name: string
}
class SelectGirls<T extends Girl> {
constructor(public girl: T[]) {}
getGirl(index: number):string {return this.girl[index].name}
}
let g = new SelectGirls([
{name: 'lyz',age: 21},{name: 'my',age: 22},{name: 'lyj',age: 11}
])
console.log(g.getGirl(2))
命名空间
// html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./build/page.js"></script>
</head>
<body>
<script>
new Home.Page()
</script>
</body>
</html>
// ts文件
//components.ts
namespace Components {
export class Header {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'Header'
document.body.appendChild(elem)
}
}
export class Content {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'Content'
document.body.appendChild(elem)
}
}
export class Footer {
constructor() {
const elem = document.createElement('div')
elem.innerText = 'Footer'
document.body.appendChild(elem)
}
}
}
//page.ts
namespace Home {
export class Page {
constructor() {
new Components.Header()
new Components.Content()
new Components.Footer()
}
}
}
装饰器
装饰器是一种特殊类型的声明,它能够被添加到类声明,方法、属性或参数上,可以修改类的行为。
常见的装饰器:类装饰器、属性装饰器、方法装饰器、参数装饰器。
装饰器的写法:普通装饰器(无参数)、装饰器工厂(可传参)。
类装饰器
// 普通装饰器
function logClass(params: any) {
console.log(params)
params.prototype.apiurl = '动态扩展属性'
params.prototype.say = function() {
console.log('say')
}
}
@logClass
class HttpClient {
constructor() {}
}
let h = new HttpClient()
console.log(h.apiurl)
h.say()
// 装饰器工厂
function logClass(params: string) {
return function(target: any) {
console.log(target)
console.log(params)
target.prototype.uname = params
}
}
@logClass('lyz')
class HttpClass {
constructor() {}
}
let h = new HttpClass()
console.log(h.uname)
类装饰器会在运行时被当做函数调用,类的构造函数作为唯一的参数。
如果装饰器返回一个值,他会使用提供的构造函数来替换类的声明。
// 类装饰器重载构造函数
function logClass(params: any) {
return class extends params {
uname: any = '我是修改后的uname'
getUname(){
this.uname = this.uname +'-------'
console.log(this.uname)
}
}
}
@logClass
class HttpClass {
public uname: string | undefined
constructor() {
this.uname = 'uname'
}
getUname() {
console.log(this.uname)
}
}
let h = new HttpClass()
h.getUname()
属性装饰器
属性装饰器会在运行时当做函数被调用,传入两个参数:
- 对于静态成员来说是类的构造函数,对于实力成员是类的原型;
- 成员的名字。
function logParam(params:any) {
return function(target: any, attr: any) {
console.log(target)
console.log(attr) // uname
target[attr] = params
}
}
class LogCons {
@logParam('lyz')
public uname: any
constructor() {}
getName() {
console.log(this.uname) // lyz
}
}
let h = new LogCons()
h.getName()
方法装饰器
方法装饰器会被应用到方法的属性描述符上,可以用来监视,修改或替换方法定义。
方法装饰器会在运行时传入下列三个参数:
- 对于静态成员来说是类的构造函数,对于实力成员是类的原型;
- 成员的名字;
- 成员的属性描述符。
这里是引用。
function get(params: any){
return function(target: any, getMethodName: any, desc: any) {
console.log(target)
console.log(getMethodName)
console.log(desc)
target.api = 'xxx'
target.run = function(){
console.log('run')
}
}
}
class GetFun {
public url: any | undefined
constructor(){}
@get('lyz')
getName() {
console.log(this.url)
}
getAge(){}
}
let g = new GetFun()
console.log(g.api)
g.run()
g.getName()
// 修改
function get(params: any){
return function(target: any, getMethodName: any, desc: any) {
console.log(target)
console.log(getMethodName)
console.log(desc.value)
// 把当前参数修改为string类型
// 保存当前方法
let oMethod = desc.value
desc.value = function(...arg: any[]){
arg = arg.map( ele =>{
return String(ele)
})
console.log(arg)
oMethod.apply(this, arg)
}
}
}
class GetFun {
public url: any | undefined
constructor(){}
@get('lyz')
getName(...arg: any[]) {
console.log(arg)
}
getAge(){}
}
let g = new GetFun()
g.getName(99, 11, 23)
方法参数装饰器
方法参数装饰器表达式会在运行时当做函数被调用,可以使用方法参数装饰器为类的原型增加一些元素数据,传入下列三个参数:
- 对于静态成员来说是类的构造函数,对于实例成员是类的原型;
- 方法的名称;
- 参数在函数参数列表中的索引。
function get(params: any){
return function(target: any, methodName: any, paramsIndex: any) {
console.log(target)
console.log(methodName)
console.log(paramsIndex)
console.log(params)
}
}
class GetFun {
public url: any | undefined
constructor(){}
getName(@get('nname')uname: any) {
console.log(uname)
}
}
let g = new GetFun()
g.getName('lyz')
执行顺序
同一类型从右向左(从下向上)
不同类型:属性装饰器>方法装饰器>方法参数装饰器>类装饰器