视频地址 https://www.bilibili.com/video/av38379328/?p=3
- 定义未赋值,设置默认值
let a:number | undefined;
a;// undefined
a = 3;
a; // 3- 定义数组
// 方式1
let arr: string = ["aa", "bb"]
// 方式2
let arr:Array<String> = ["aa", "bb"]- 定义枚举
enum flag {success: 1, error: 2}
let leo:flag = flag.errorenum Color {blue , red, 'orange'}
let c:Color = Color.red
c; // 1如果标识没有赋值 则它的值就是下标
enum Color {blue , red = 3, 'orange'}
let c:Color = Color.red
c; // 3- 定义 void 类型,没有返回值
function fun():void {
}
// 不能使用undefined
function fun():undefined {
}- 定义
never类型
包括 null 和 undefined 类型,是其他类型的子类型,代表从不会出现的值。
用 never 声明的变量只能用 never 类型的值所赋值。
let a:never;
a = 11; // err- 可选参数
必须定义在参数最后一个
function fun(name:string, age?:number){
// ....
}- 剩余参数
三点运算符
function fun(...res:number[]):number{
// ....
}- 函数重载
function fun(name:string){
// ....
}function fun(age:number){
// ....
}这时候 fun 方法 就有2个参数,重载不会覆盖
- 实例方法和静态方法
以 jquery 为例:
// 静态方法 直接使用
$.get(....)
// 实例方法 需要先实例化
$('.dom').css(....)ts 中静态方法:
class Per {
static leo = "hi"
static print () {
console.log(Per.leo)
}
}
// 使用静态属性
Per.leo
// 使用静态方法
Per.print()- 多态
父类定义一个方法不去实现,让继承它的子类去实现,每个子类有不同的表现。
class A {
name: string
constructor(name:string){
this.name = name
}
eat (){ console.log('吃···') }
}
class B extends A {
constructor(name:string){
super(name)
}
eat (){
return this.name + '哈哈哈'
}
}- 抽象类
它提供其他类继承的基类,不能直接实例化。
用 abstract 关键字定义抽象类和抽象方法。
可以说抽象类和抽象方法使用来定义标准。
抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。
// 抽象类必须有抽象方法
// 抽象方法必须在抽象类中
abstract class A {
public name: string
constructor(name:string){
this.name = name
}
abstract eat (){ console.log('吃···') }
}
// 抽象类的子类必须实现抽象类里面的抽象方法
class B extends A {
constructor(name:string){
super(name)
}
eat (){
return this.name + '哈哈哈'
}
}
let aa = new B(' hello ')行为和动作的规范,对批量方法进行约束。
- 属性类型接口
interface Name {
fName: string; // 必须
sName?: string; // 可选
}
function F(name:Name){
console.log(name.fName, name.sName)
}- 函数类型接口
interface f{
(key: string, value: string): string
}
let md5:f = function(key: string, value: string): string{
return key + value
}- 可索引接口 (约束数组、对象)
interface Arr {
[index: number]: string
}
let a: Arr = ["aa", "bb"]
interface Obj {
[index: string]: string
}
let o: Obj = {
aa: 'aaa',
bb: 'bbb'
}- 类类型接口
implements 实现后面的接口。
interface C {
name: string;
fun(str: string):void;
}
class P implements C {
name: string
constructor(name: string){
this.name = name
}
fun(){
console.log(this.name + 'in here~')
}
}
let aa = new P('leo')- 接口拓展
接口继承其他接口。
interface A {
fun1():void;
}
interface B extends A{
fun2():void;
}
class C implements B {
public name: string;
constructor(name: string){
this.name = name
}
fun1(){ console.log(this.name) }
fun2(){ console.log(this.name) }
}
let p = new C()
p.fun1('leo')简单理解:泛型就是解决类、接口和方法的复用性,以及对不特定数据类型的支持。
可以使用泛型来创建可重用的组件,一个组件支持多种类型的数据。
- 普通写法:
// 只能返回一种类型
function fun1 (name: string): string{
return name;
}
// 可以返回多种类型
// 使用 any 则放弃使用类型检查
function fun2 (name: any): any {
return name;
}- 使用泛型:
由于如果使用 any 可能出现可以传入 string 返回 number ,所以需要使用泛型,使得传入参数和返回类型参数一致。
T 表示泛型,具体什么类型是调用这个方法的时候决定的。
function fun3<T>(name: T): T{
return name;
}
fun3<number>(123); // 调用方法的时候决定
fun3<string>('123');class C<T>{
public list:T[] = [];
fun1(name: T):void{
this.list.push(name)
}
fun2():T{
return this.list[0]
}
}
let a1 = new C<number>()- 方法1:
interface Config{
<T>(name: T): T;
}
let getData : Config = function<T>(name: T): T{ return name; }
getData<number>(123);
getData<string>('aaa');- 方法2:
interface Config{
(name: T): T;
}
function getData<T>(name: T): T{ return name; }
let fun1: Config<string> = getData;
fun1('aaa')- 以前将类作为参数类型,可以检查参数是否类型符合
class User{
name: string | undefined;
pwd: string | undefined;
}
class Db {
add(data: User): boolean{ return true }
}
let dd = new Data();
dd.name = "aaa";
dd.pwd = "1233";
let D = new Db()
D.add(dd);- 把类作为参数类型的泛型类
class Db<T>{
add(data: T): boolean{ return true }
}
class Data{
name: string | undefined;
pwd: string | undefined;
}
let dd = new Data();
dd.name = "aaa";
dd.pwd = "1233";
let D = new Db<Data>()
D.add(dd);export 暴露模块, import 导入模块。
- 方式1
// 1.js
export fun(){}
export let a = 1
// 2.js
import { fun, a } from './1.js'
fun()- 方式2
// 1.js
fun(){}
let a = 1
export { fun, a }
// 2.js
import { fun, a as ha } from './1.js' // 将 a 重命名为 ha
fun()- 方式3 默认导出
// 1.js
export default fun (){}
// 2.js
import fun from './1.js'在模块内部,用于组织代码,避免命名冲突。
使用 namespace 关键字作为划分,将指定的代码放到命名空间中,并使用 export 暴露其中变量和方法(类似将命名空间当做模块),调用的时候,需要使用 空间名称 来获取对应变量方法。
namespace A{
interface Leo{
name: string
}
export let aa = 1;
// ....
}
namespace B{
interface Leo{
name: string
}
export let aa = 2;
// ....
}
console.log(A.aa) // 1
console.log(B.aa) // 2是一种特殊类型的声明,能够被附加到类生命,方法,属性或参数上,可以修改类的行为。
常见:类装饰器,属性装饰器,方法装饰器,参数装饰器。
装饰器写法:普通装饰器(无法传参),装饰器工厂(可传参)
// 类装饰器
function myClass(params: any){
// params 当前类
params.prototype.url = 'www.xxx.com'
params.prototype.fun1 =function (){
console.log('fun')
}
}
@myClass
class FunClass{
constructor(){ }
fun(){ }
}
let a: any = new FunClass()
a.url; // 'www.xxx.com'
a.fun1(); // 'fun'// 类装饰器
function myClass(params: string){
// params 传入参数
// target 当前类
return function (target: any){
console.log(params, target)
target.prototype.url = params
}
}
@myClass('www.xxx.com')
class FunClass{
constructor(){ }
fun(){ }
}
let a: any = new FunClass()用来修改当前类的构造函数,属性和方法。
// 类装饰器
function myClass(target: any){
// target 当前类
return class extends target{
link : any = 'bbbbbb'
fun1(){
console.log('-----' + this.link)
}
}
}
@myClass
class FunClass{
public link : string | undefined;
constructor(){
this.link = 'aaaaaaaaaaaa'
}
fun(){
console.log(this.link)
}
}
let a: any = new FunClass()
a.fun1(); // '-----bbbbbb'// 类装饰器
function myClass(params: string){
return function (target: any){
}
}
// 属性装饰器
function myAttr(params: any){
return function (target:any , attr:any){
// target 当前类原型对象 , attr 当前属性
target[attr] = params
}
}
@myClass('www.xxx.com')
class FunClass{
@myAttr('leo')
public link : any | undefined
constructor(){ }
fun(){ console.log(this.link) }
}
let a: any = new FunClass()
a.fun(); // 'leo'用来监视、修改或替换方法的定义。
方法装饰会在运行时,传入三个参数:
- 对于静态方法来说是类的构造函数,对于实例方法是类的原型对象。
- 方法的名称。
- 方法的属性描述符。
function logMethod(params: any){
return function(target:any, methodName:any, desc:any){
console.log(target, methodName, desc)
// 拓展原型方法和属性
target.url = 'www.baidu.com'
target.leo = function(){
console.log('hi leo~~~')
}
// 修改原型方法 eg将参数转换成 string 类型
let old = desc.value;
desc.value = function(...args:any[]){
args = args.map(val => String(val))
console.log(args)
old.apply(this,args)
}
}
}
class Myclass {
public url: any | undefined;
constructor(){}
@logMethod('hi leo')
getData(){
console.log('this.url',this.url)
}
}
let my:any = new Myclass()
console.log(my.url)
my.leo()
my.getData(123,'aaa')方法参数装饰器表达式会在运行时当做函数被调用,可以使用参数装饰器为类的原型添加一些元素数据。
方法装饰会在运行时,也是传入三个参数,和方法装饰器一样。
function logMethod(params: any){
return function(target:any, methodName:any, paramsIndex:any){
console.log(params, target, methodName, paramsIndex)
target.url = 'www.baidu.com'
}
}
class Myclass {
public url: any | undefined;
constructor(){}
getData( @logMethod('uuid') uuid:any){
console.log('this.uuid',uuid)
}
}
let my:any = new Myclass()
my.getData(123)
console.log(my.url)属性装饰器 - 方法装饰器 - 方法参数装饰器 - 类装饰器
多个相同类型装饰器,会从下开始执行,比如:
@fun1('b')
@fun2('a')
class Hello {}则先执行装饰器 fun2 再执行装饰器 fun1 。