TypeScript初学

本文记录了 TypeScript 中的基础变量类型和使用方式,以及在 Vue2 框架中引入的调整。

类型

  1. 布尔值

    let isDef: boolen = false
    
  2. 数字

    let num: number = 0
    
  3. 字符串

    let str: string = 'hello word'
    
  4. 数组

    let nums: number[] = [1, 2, 3]
    
    let strs: Array<string> = ['s1', 's2', 's3']
    
  5. 元组

    元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同

    let list: [string, number] = ['hello', 1]
    
  6. 枚举

    枚举类型用于定义数值集合,默认情况从 0 开始编号,可手动指定成员数值

    enum Color { Red, Green, Blue }
    
    let c: Color = Color.Red
    
  7. Any

    声明为 any 的变量可以赋予任意类型的值

    let key: any = 1
    
    let key1: any = 'hello'
    
  8. Object

    表示非原始类型,除number,string,boolean,symbol,null或undefined之外的类型

    declare function create(o: object | null ) : void
    
    create({ prop: 0 })
    
  9. Null、Undefined

    指定了 --strictNullChecks 标记,null 和 undefined 只能赋值给 void 和它们各自

    let undef: undefined = undefined
    
    let nul: null = null
    
  10. Never

    表示的是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型;变量也可能是 never类型

    function error(message: string): never {
        throw new Error(message)
    }
    
  11. Void

    表示没有任何类型,当一个函数没有返回值时,返回值类型是 void;声明一个void类型的变量,则只能为它赋予undefined和null

    function warnUser(): void {
    	//无返回值
    	console.log("This is my warning message")
    }
    
    let unusable: void = undefined
    
  12. 类型断言

    手动指定一个类型的值,即允许变量从一种类型更改为另一种类型

    let value: any = 'hello word'
    
    let length: number = (<string>value).length
    
    let length1: number = (value as string).length
    
  13. 联合类型

    关键词 | 表示或,类型选其一

  14. 交叉类型

    关键词 & 表示与,取类型交集

  15. 类型别名

    关键词 type

赋值

  1. 变量声明

    包含 let、const、var 三种方式

    let const var
    作用域 当前代码块 当前代码块 当前函数、模块或全局
    重复赋值
    变量提升
    是否可修改
  2. 解构

    // 数组解构
    let input = [1, 2]
    let [first, second] = input
    
    // 对象解构
    let input = [1, 2]
    let [first, second] = input
    

  1. 声明

    通过关键词 class 声明一个类

    class Greeter {
    	greeting: string; 
    
    	constructor(message: string) {
    	    this.greeting = message;
    	}
    	
    	greet() {
    	    // this 指向类实例
    	    return "Hello, " + this.greeting;
    	}
    
    }
    
  2. 实例创建

    let greeter = new Greeter('word')
    
  3. 修饰词

    对类的属性和方法进行访问的定义,默认只为 public

    含义 描述
    readonly 只读 只在构造函数中可以赋值
    public 公共 可以在实例、实例方法和子类访问
    private 私有 只在实例的方法中访问
    protected 保护 可以在子类和实例方法中访问
    static 静态 通过类名访问
    abstract 抽象
  4. 继承

    子类通过关键词 extends 继承父类:子类可以访问父类中的公共和保护属性、方法;子类可以赋值给父类

    // 父类 Animal
    class Animal {
        
    }
    
    // 子类 Dog
    class Dog extends Animal {
        
    }
    
  5. 存取器

    类属性的赋值和读取方法

    class Employee {
        private _fullName: string;
    
        get fullName(): string {
            return this._fullName;
        }
    
        set fullName(newName: string) {        
            this._fullName = newName;
        }
    }
    
  6. 抽象类

    通过关键词 abstract 创建,不能被实例化,可以被继承;

函数

  1. 类型定义

    函数的类型包括参数类型和返回值类型;传递给一个函数的参数个数必须与函数期望的参数个数一致

    function add(x: number, y: number): number {
        return x + y;
    }
    
    let add1: (x: number, y: number) => number = 
        function(x: number, y: number): number { return x + y; }
    
  2. 可选参数

    可以通过 ? 实现可选参数功能;可选参数必须在必须参数之后

    function add(x: number, y?: number): number {
        return y ? (x + y) : x;
    }
    
  3. 默认参数

    在函数声明的时候,设置参数的值。函数调用时,不传入该参数或传入 undefined 时,参数取设置的默认值

    function add(x = 1, y: number): number {
        return x + y;
    }
    
  4. 剩余参数

    剩余参数的接收方式为数组

    function add(x: number, ...rest: number[]): number {
        return rest.reduce((acc, cur) => acc + cur, x)
    }
    
  5. this 参数

    this参数是个假的参数,它出现在参数列表的最前面,指向当前作用域对象

    interface Deck {
        suits: string[];
        createCardPicker: (this: Deck) => void;
    }
    
    let deck: Deck = {
        suits: ["hearts", "spades", "clubs", "diamonds"],
        createCardPicker: function (this: Deck) {
            console.log(this.suits[0])
        }
    }
    
    deck.createCardPicker()  // 输出:hearts
    
  6. this 指向

    指向
    普通函数 函数所在作用域对象
    匿名函数 全局对象
    箭头函数 函数所在作用域指向的对象
  7. 函数重载

    函数名相同,参数个数或类型不同;调用时会匹配第一个符合条件的函数

    function add(x: number): number {
        return x + 1
    }
    
    function add(x: number, y: number): number {
        return x + y
    }
    

接口

​ 不会检查属性的顺序,只需相应的属性存在且类型正确即可

  1. 可选属性

    interface LabelledValue {
        label: string;
    }
    
  2. 只读属性

    interface SquareConfig {
    	color?: string;
    	width?: number;
    }
    
  3. 额外属性检查

    interface SquareConfig {
        color?: string;
        width?: number;
        [propName: string]: any;
    }
    
  4. 函数类型

    包含参数列表和返回值类型的函数定义,参数列表里的每个参数都需要名字和类型

    interface SearchFunc {
    	(source: string, subString: string): boolean;
    }
    
    let mySearch: SearchFunc;
    mySearch = function(source: string, subString: string) {
        let result = source.search(subString);
        return result > -1;
    }
    
  5. 可索引的类型

    支持两种索引签名:字符串和数字,可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型

    interface StringArray {
        [index: number]: string;
    }
    
    let myArray: StringArray;
    myArray = ["Bob", "Fred"];
    
    let myStr: string = myArray[0];
    
  6. 类类型

    类可以通过 implements 实现一个接口规范,接口只对类实例进行约束

    interface ClockInterface {
        currentTime: Date;
        setTime(d: Date);
    }
    
    class Clock implements ClockInterface {
        currentTime: Date;
        setTime(d: Date) {
            this.currentTime = d;
        }
        constructor(h: number, m: number) { }
    }
    

泛型

  1. 泛型使用

    在函数和类声明的时候,以占位符的形式定义参数类型,在调用时传入具体的参数

    function add<T>(x: T, y: T): T {
        return x + y;
    }
    
    let acc = add<number>(2, 3)
    
    class Arithmetic<T> {
        add(x: T, y: T): T {
        	return x + y;
    	}
    }
    
    let arithmetic = new Arithmetic<number>()
    let acc = arithmetic.add(2, 3)
    
  2. 泛型约束

    通过 extends 可以对泛型进行类型限制

    interface Lengthwise {
        length: number
    }
    
    function computeLength<T extends Lengthwise>(value: T): number {
        return value.length
    }
    

装饰器

  1. 装饰器是一种特殊类型的声明,本质上就是一个方法,可以注入到类、方法、属性、参数上,扩展其功能;在运行时会执行该方法

    @f x
    
    签名
    类装饰器 declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction
    方法装饰器 declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void
    属性装饰器 declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void
    参数装饰器 declare type ParamDecorator = (target: Object, propertyKey: string | symbol, index: number) => void

    target 当前对象原型;propertyKey 方法、属性、参数名称;descriptor 方法的属性描述符;index 参数数组中的位置

  2. 装饰器工厂

    通过闭包的形式,返回一个函数,实现向装饰器传入参数

    function color(value: string) {
        return function (target: Function){
            //TODO
        }
    }
    
    @color('red')
    class ColorRed {
        
    }
    
  3. 执行顺序

    装饰器工厂:先执行工厂函数,然后执行装饰器函数

    多个装饰器:装饰工厂函数有上向下执行;装饰器函数由下向上执行

    function f() {
        console.log("f(): evaluated");
        return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
            console.log("f(): called");
        }
    }
    
    function g() {
        console.log("g(): evaluated");
        return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
            console.log("g(): called");
        }
    }
    
    class C {
        @f()
        @g()
        method() {}
    }
    

    执行结果

    f(): evaluated
    g(): evaluated
    g(): called
    f(): called
    
  4. Vue2 使用

    需要安装 vue-property-decorator 插件

    npm install vue-property-decorator --save
    
    import { Vue, Component, Prop, Watch, Ref, Emit } from 'vue-property-decorator'
    
    @Component // 组件,引入组件时 @Component({ components: { ... } })
    export default class CommonMenu extends Vue {
        // 生命周期
        created(){
            
        }
        // 属性
        @Prop({ type: String, default: '' }) readonly name?: 'Li';
        // 响应式数据
        message: string = 'hello';
        // 计算属性
        get greet() {
            return `${this.message},${this.name}`;
        }
        // 数据监听
        @Watch('name', {})
        changeName(val: String, oldVal: String) {
            console.log(`watch: ${val}/${oldVale}`)	
        }
        // 方法
        hello() {
            console.log(`hello word`)
        }
        // ref
        @Ref('header') readonly headerRef!: any;
    	// 向父组件传值:接收方式 @change-msg="",默认为方法名称
    	@Emit('changeMsg')
    	handleMsg() {
            return this.message // 要传递的值
        }
    }
    

命名空间

  1. 通过代码块的形式分割变量、函数和类的声明,以 export 形式导出可访问项

    namespace Validation {
        export interface StringValidator {
            isAcceptable(s: string): boolean;
        }
    }
    
  2. 导入

    通过 /// <reference path="xxx.ts" /> 形式引入命名空间

    // shapes.ts
    namespace Shapes {
        export namespace Polygons {
            export class Square {
                readonly name: string
                constructor() {
                    this.name = 'Square';
                }
            }
        }
    }
    
    /// <reference path="shapes.ts" />
    
    import polygons = Shapes.Polygons;
    let sq = new polygons.Square();
    
  3. 别名

    通过 import q = x.y.z 形式对常用对象进行重新命名

    import polygons = Shapes.Polygons;
    

    原文链接:TypeScript初学

上一篇:PHP对象和数组的相互转换


下一篇:php引用(&)详解及注意事项