TS笔记

128 阅读3分钟

/**
 * 声明字符串
 */
let str: string = 'TS';
let temp: string = `web${str}`;

/**
 * 声明数字
 */
let num: number = 123

/**
 * 声明布尔值
 */
let bool: boolean = 2 > 3
let bool2: boolean = false

/**
 * 声明空值
 */
let nu: void = null
let nu2: void = undefined
console.log(nu)
// 申明方法的返回值为空或者是没有返回值
function fn(): void {
    console.log(111)
    return null
}
let nu3: null = null
let nu4: undefined = undefined
let nu5: undefined = null
let nu6: null = undefined
nu6 = nu3
console.log(nu3)
// 注:void 类型不能赋值给其他类型,包括null/undefined

/**
 * 未知类型  any 和 unknown
 * any 和 unknown 的区别
 * 1.unknown类型是不能调用它里面的属性或方法的,any可以
 * 2.unknown类型只能赋值给它自身或 any, 不能赋值给其他类型
 */

let test_any: any = 'str'
test_any = {}
test_any = []
test_any = null
test_any = Symbol('111')

let temp: unknown = { a: 123 }
let temp2: unknown = 'str'


/**
 * 类型推论 
 */
let num10 = 3     // 等价于 let num10: number = 3
num10 = 123  // 会报错,如果申明时没有指定类型,则推论初始化赋值的类型
let num12   // 如果初始化没有赋值,则为any任意类型 等价于 let num10: any
num12 = {}
num12 = 123

/**
 * 联合类型 
 */

let lh1: string | number = 123
lh1 = 'jp'
console.log(lh1.length) // 字符串有length属性,没有问题
lh1 = 123
console.log(lh1.length) // 这里就会报错,number没有length属性

/**
 * interface 接口类型
 * interface 名字相同会自动合并
 */

// interface 中定义的属性一直(不多不少),同时数据类型也要相同
interface A {
    name: string
    age: number
}
let A1: A = {
    name: 'jp',
    age: 12
}
// interface 可选式操作符,可以有这个属性也可以没有这个属性 ?
interface B {
    name: string
    age?: number  // 冒号前面加上问好就是可选属性,可以有也可以没有
}
let B1: B = {
    name: 'jp',
}

// 接口继承接口

interface A{
    name:string,
    age:number
}
interface B extends A{
    city:String
}
let ab:B ={
    age:12,
    name:'jp',
    city:'xi,an'
}

// interface [propName:string]:any 对象中可以有任意属性
interface C {
    [propName: string]: any
}
let C1: C = {
    name: 'jp',
    obj: {}
}
// readonly 只读类型
interface D {
    readonly name: string // 只读属性
}
let D1: D = {
    name: 'jp'
}
D1.name = 'ccc' // 只能读,修改会报错
// interface 继承 extends
interface E extends B {  // E 接口继承了 A接口的属性类型
    a: string[]
}
let E1: E = {
    name: 'jp',
    age: 122,
    a: ['1']
}
// interface 中定义函数
interface F {
    fn(): void, // 定义一个没有返回值,或则返回值为null/undefined的方法
    fun(): object  // 定义一个返回值为object的方法
}

let F1: F = {
    fn() {
        console.log(123)
    },
    fun() {
        return { a: 1 }
    }
}



/**
 * 定义数组
 * 两种方式  元素类型后面接上[] string[] | 泛型Array<string>
 */
// 第一种,元素类型后面接上[]
let arr: number[] = [1, 2]
let arr2: string[] = ['1', '2']
let arr3: boolean[] = [false, true]
let arr4: any[] = [false, true, {}, 1, 'str']
let arr8: number[][][] = [[[]], [[]]]

// 第二种,使用数组泛型Array<元素类型>
let arr5: Array<number> = [1, 2]
let arr6: Array<string> = ['1', '2']
let arr7: Array<boolean> = [false, true]
let arr9: Array<Array<number | string>> = [[1, '2']]

function ArrFunction(...args: any): void {
    // IArguments  接受方法的参数集合时,因为时类数组,需要使用IArguments
    // typescript内置了名为IArguments 的 interface接口对象
    // interface:IArguments{
    //     [index:number]:any,
    //     length:number,
    //     callee:Function
    // }
    let arr: IArguments = arguments
}

/**
* 定义函数
* 一个函数有输入和输出,typeScript会对其进行约束
*/

// 函数声明
function fun1(num: number, str: string): string {
    return num + str
}

// 函数表达式
// fun2 的类型是通过推论得到的
let fun2 = function (num: number, str: string): string {
    return num + str
}

// 通过接口定义函数的形状
interface Ifn {
    (num: number, str: string): string
}
let fun3: Ifn
// 使用interface 定义函数时 入参名可以不和函数中一致,函数中参数也可以不指定类型,TS会自动推论
fun3 = function (a, b) {
    return a + b
}

// 函数可选参数,在定义函数参数类型时加上? ,表示为可选参数
let fun4 = function (firstName: string, lastName?: string): string {
    if (lastName) {
        return firstName + lastName
    } else return firstName
}

let strFun4: string = fun4('j')
strFun4 = fun4('j', 'p')

// 函数参数默认值
// 可选参数后面不能有必须参数,如果需要这样操作,就要给后面的必选参数添加一个默认值,typeScript就会将后面的参数也默认为可选参数
let fun5 = function (firstName?: string, lastName: string = 'p'): string {
    if (firstName) {
        return firstName + lastName
    } else return lastName
}

// 函数剩余类型
function push(arr: any[], ...items: any[]) {
    items.forEach(item => {
        arr.push(item)
    })
}
let a = []
push(a, 1, 2, 3, 4, 5)

// 函数的重载
function reverse(x: string | number): string | number {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join())
    } else return x.split('').reverse().join()
}

/**
 * 类型断言 将一个联合类型,断言为一个指定类型
 */
//    值 as ITwo (params as ITwo )
//    <ITwo>值   泛型断言 

interface IOne {
    name: string,
    funOne(): void
}
interface ITwo {
    name: string,
    funTow(): void
}
function tempFun(params: IOne | ITwo): boolean {
    if (typeof (params as ITwo).funTow === 'function') {
        return true
    } else return false
}
// 还有比较多的断言方式,时间关系没有学习,后续用到在学

/**
 * type 关键字
 */

// type 关键字给类型取别名

type Name = string
type MyFun = () => string
type MyStrFun = string | MyFun

function getName(n: MyStrFun): Name {
    if (typeof n === 'string') {
        return n
    } else return n()
}

getName(() => {
    return 'jp'
})
getName('jp')

// type 字面量别名,值别名

type EventNames = 'click' | 'scroll' | 'mousemove'

function handleEvent(ele:Element,event:EventNames){

}

handleEvent(document.querySelector('body'),'click')  // 没问题
handleEvent(document.querySelector('body'),'dblclick') // 报错,event不能为 dblclick

/**
 * 元祖类型
 */

// 声明
let tom:[string,number] = ['interface',15]

// 获取 修改
console.log(tom[0])

tom[0] = 'any'

tom = ['void',25]

// tom = ['sync']   不能这样赋值,会报错

// 添加越界元素时,只能添加联合类型的类型,也就是元祖声明时指定的类型
tom.push('await')

tom.push(18)

// 元祖初始声明中没有的联合类型,会报错
tom.push(true)


/**
*枚举
*/
enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat }

// 通过下标的方式进行访问
console.log(Days['Sun'] === 0)  // true
console.log(Days['Mon'] === 1)  // true
console.log(Days['Tue'] === 2)  // true
console.log(Days['Wed'])        // 3

console.log(Days[0] === 'Sun')  // true
console.log(Days[1] === 'Mon')  // true
console.log(Days[2] === 'Tue')  // true
console.log(Days[3])            // Wed

// 编译为js后如下
// var Days;
// (function (Days) {
//     Days[Days["Sun"] = 0] = "Sun";
//     Days[Days["Mon"] = 1] = "Mon";
//     Days[Days["Tue"] = 2] = "Tue";
//     Days[Days["Wed"] = 3] = "Wed";
//     Days[Days["Thu"] = 4] = "Thu";
//     Days[Days["Fri"] = 5] = "Fri";
//     Days[Days["Sat"] = 6] = "Sat";
// })(Days || (Days = {}));
// console.log(Days['Sun'] === 0); // true
// console.log(Days['Mon'] === 1); // true
// console.log(Days['Tue'] === 2); // true
// console.log(Days['Wed']); // 3

/**
 * 类 构造函数
 */
class SayName {
    public _name // 类中的公共属性需要在这里定义,否则会报错
    constructor(name: string) {
        this._name = name
    }
    sayHi() {
        return `my name is ${this._name}`
    }
}

let say = new SayName('jp')
console.log(say.sayHi())

/**
 * 类 取存器 getter / setter
 */
class GetSet {
    // public name
    constructor(name: string) {
        this.name = name
    }
    get name() {
        return 'jp'
    }
    set name(val) {
        console.log('setter:' + val)
    }
}
let getSet = new GetSet('_jp')
console.log(getSet.name)
getSet.name = 'CCC'
console.log(getSet.name)

/**
 * 类 静态方法 static
 */
class SayName {
    public name
    constructor(name: string) {
        this.name = name
    }
    sayHi() {
        return `My name is ${this.name}`
    }
    static sayHello() {
        return `hello jp`
    }
}

let sayName = new SayName('jp')

// 非静态方法,通过类的实例来调用
console.log(sayName.sayHi())  // My name is jp
// 静态方法使用static来修饰,使用的时候直接通过构造函数来调用
console.log(SayName.sayHello())  //hello jp


/**
 * 类 修饰符 public 公共的、private 私有的、 protected 受保护的 
 */

// public 公共的、全局的都可以使用
class Test1 {
    public _name
    constructor(name: string) {
        this._name = name
    }
}
let a = new Test1('jp')
console.log(a._name)  // jp
a._name = 'jdp'
console.log(a._name)  // jdp

// private 私有的,只能在类的内部使用,不能在子类中别继承和使用,也不能在实例化对象中使用
class Test2 {
    private _name
    constructor(name: string) {
        this._name = name
    }
}
let a1 = new Test2('jp')
console.log(a1._name)  // 提示报错, _name只能在类的内容使用
a1._name = 'jdp'
console.log(a1._name)  // jdp

// protected 受保护的   可以允许子类继承使用,不能在实例化对象中使用

class Test3 {
    protected _name
    constructor(name: string) {
        this._name = name
    }
}
class Test4 extends Test3 {
    constructor(name: string) {
        super(name)
        console.log(name)
    }
}

/**
 * 类  简洁声明构造函数、只读关键字 readonly
 */
class Test {
    public _name: string
    constructor(name) {
        this._name = name
    }
}
// 简写为
class Test2 {
    constructor(public _name: string, name) {
        this._name = name
    }
}

// 类中声明只读属性
class Test3 {
    readonly _name: string
    constructor(name: string) {
        this._name = name
    }
}

let test3 = new Test3('jp')
console.log(test3._name)

test3._name = 'ccc' // 会报错,因为是只读属性

/**
 * 抽象类 abstract
 * abstract 用于定义抽象类、和抽象方法
 * 抽象类是不允许实例化的
 */

//  抽象类本身是不允许实例化的,需要通过 子类去继承,并且由子类去实现抽象类的抽象方法
abstract class Test1{
    public _name
    constructor(name:string){
        this._name = name
    }
    public abstract sayHi():void
}

let a = new Test1('jp') // 报错 无法创建抽象类的实例

// 子类继承后,必须实现抽象方法,否则会报错
class Test2 extends Test1{
    public sayHi(): void {
        console.log(this._name)
    }
}

/**
 * 泛型 
 * 泛型是指在定义接口、函数、或类的时候,不预选指定具体的类型,而在使用的时候在指定类型的一种特性
 */

// 这里指定的类型不够精确
function createArray(length: number, value: any): Array<any> {
    let result: any[] = []
    for (let i = 0; i < length; i++) {
        result.push(value)
    }
    return result
}

let a = createArray(3, 'cc')
console.log(a)


// 泛型写法  通过泛型指定具体类型 ,在方法后面加上<T>,T就代表具体指定的类型
function cerateArrayType<T>(length: number, value: T): Array<T> {
    let result: T[] = []
    for (let i = 0; i < length; i++) {
        result.push(value)
    }
    return result
}

let aType = cerateArrayType<string>(3,'pp')  // 掉用的时候通过<指定的类型>
let aType2 = cerateArrayType(3,'V')   // 不指定类型,自动使用TS的类型推论
console.log(aType)
console.log(aType2)

/**
 * 泛型 多个类型参数
 */

function fun<T, U>(temp: [T, U]): [T, U] {
    return [temp[0], temp[1]]
}

let a = fun<string, number>(['jp', 2])
console.log(a)  // ['jp',2]
// TS类型推论
let b = fun([2, 'jp'])
console.log(b)  // [2,'jp']

/**
 * 泛型约束 
 */

// 下面的方法中,由于不确定temp参数的有没有length属性,所有会报错,这个时候就需要使用泛型约束
// function fun<T>(temp:T):T{
//     console.log(temp.length)
//     return temp
// }

// 泛型约束写法

// 定义一个接口
interface ITemp {
    length: number
}

// 约束   让它继承ITemp这个接口
function fun2<T extends ITemp>(temp: T): T {
    console.log(temp.length)
    return temp
}

fun2(2)  // number 没有length属性 会报错
fun2([1,2]) // 有length属性 没问题

/**
 * 泛型接口
 */
// 第一种写法
interface ITemp2 {
    <T>(length: number, value: T): Array<T>
}

let createArray2: ITemp2

createArray2 = function <T>(length: number, value: T): T[] {
    let result: T[]
    for (let i = 0; i < length; i++) {
        result.push(value)
    }
    return result
}

// 第二种写法
interface ITemp<T> {
    (length: number, value: T): T[]
}

let createArray: ITemp<any>

createArray = function <T>(length: number, value: T): T[] {
    let result: T[]
    for (let i = 0; i < length; i++) {
        result.push(value)
    }
    return result
}

/**
 * 泛型类  泛型默认值
 */

class Temp<T>{
    public age: T
    public add: (x: T, y: T) => T   // 给类定义一个公共方法,返回一个类型为T的值
}

let temp1 = new Temp<number>()
temp1.age = 12
temp1.add = function (x, y) {
    return x + y
}
let num = temp1.add(12, 14)
console.log(num)

// 泛型指定默认值 <T = string>
function createArray<T = string>(length: number, value: T): T[] {
    let result: Array<T>
    for (let i = 0; i < length; i++) {
        result.push(value)
    }
    return result
}