TypeScript语法规范

TypeScript是JavaScript的超集,提供了更严格的类型声明,方便在静态类型检查时就避免因为类型问题产生的bug。

工欲善其事,必先利其器,让我们来看看TypeScript是怎样声明数据类型的

一. 声明

1. 基本数据类型+ts特有类型void声明

/**
* Note: 未指定类型时,  TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型
* 如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查
* let a = 7
* a = 'seven' // Error:不能将类型“"seven"”分配给类型“number”
*/
const num:number = 123
const str:string = '123'
const bool:boolean = true
const und:undefined = undefined
const nu: null = null
let u: void;
console.log(num,str,bool,und,nu, u) // 123 '123' true undefined null undefined

2. 任意值类型

let everyOne: any = 'seven';
console.log(everyOne)
everyOne = 7
console.log(everyOne)
console.log(everyOne.name)

3. 联合类型,表示取值可以为多种类型中的一种

// 用|表示联合
let test: string | number;

4. 对象类型-接口

/** 
 * Note: 定义的变量不允许比接口属性少或多,形状必须和接口一致
 * 如果希望不完全匹配,可使用可选属性(该属性可以不存在,但仍不允许添加)
 * interface Person {
 *     name: string;
 *     age?: number;
 * }
 * 
 * 要添加的话使用任意属性
 * interface Person {
 *     name: string;
 *     age?: nuber;
 *     [propName: string]: any;
 * }
 * */ 
interface Person {
    readonly id: number; // 只读属性
    name: string;
    age?: number;   // 可选属性
    [propName: string]: any; // 任意属性
}
t
let tom: Person = {
    id: 123,
    name: 'TOM',
    age: 25,
    gender: '女'
}

5. 数组类型

5.1 数组+方括号表示法

let fib:number[] = [1,2,3]
// let fib1:number[] = [1,2,3,'1'] // 不能将类型“string”分配给类型“number”

5.2 数组泛型

let fibonacci: Array<number> = [1, 1, 2, 3, 5];

5.3 接口表示

interface NumberArray {
    [index: number]: number;
}
let fib1: NumberArray = [1,2,3]

6. 类数组

/** 
 * Note: 
 * 类数组不是数组类型,如arguments,dom queryselector
 * 通常用接口表示,可以自定义接口,也可用TypeScript封装的接口
 */
interface IArguments {
    [index: number]: any;
    length: number;
    callee: Function;
}
function sum() {
    let args: IArguments = arguments
    console.log(args)
}

let liList: HTMLCollection = document.getElementsByTagName('li')

7. 函数声明

7.1 函数对输入输出类型进行约束

function sum2(x: number, y: number): number {
    return x + y;
}

7.2 函数表达式

/**
 * Note: 
 * 下面表达式等号右边的为函数声明, 左边的是对mySum变量的约束
 * 左边的=>与es6中的箭头函数意义不同,代表的是函数类型,箭头左边为输入类型,右边为输出类型
 */
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
    return x + y;
};

7.3 接口定义函数

interface SearchFunc {
    (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    return source.search(subString) !== -1;
}
// 可选参数, 可选参数后面不允许再出现必需参数,可以跟默认参数
function buildName(name?: string, age: number = 0){
    return name + age
}
// 剩余参数, rest参数只能是最后一个参数
function push(array, ...items: any[]){
    items.forEach(function(item){
        array.push(item);
    })
}
// 函数重载,当函数体中有分支时,可能返回不同类型的值,可以使用重载
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

二. 声明文件

当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能
声明文件必需以 .d.ts 为后缀

声明文件中下面命令代表含义:

declare var 声明全局变量
declare function 声明全局方法
declare class 声明全局类
declare enum 声明全局枚举类型
declare namespace 声明(含有子属性的)全局对象
interface 和 type 声明全局类型
export 导出变量
export namespace 导出(含有子属性的)对象
export default ES6 默认导出
export = commonjs 导出模块
export as namespace UMD 库声明全局变量
declare global 扩展全局变量
declare module 扩展模块
/// <reference /> 三斜线指令

1. 全局变量

declare var $: (selector: string) => any;

2. 全局函数

declare function jQuery(selector: string): any;

3. 声明全局类

declare class Animal {
    name: string;
    constructor(name: string);
    sayHi(): string;
}

4. 枚举

declare enum Directions {
    Up,
    Down,
    Left,
    Right
}

5. 声明合并

// jQuery即是一个函数,又是一个对象,有自己的属性
declare function jQuery(selector: string): any;
declare namespace jQuery {
    function ajax(url: string, settings?: any): void;
}

三. 进阶声明

类型别名与字符串字面量类型都是使用 type 进行定义

1. 类型别名

// 为string起个类型别名Name
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
// 声明时可用Name代表string类型
let name1: Name = '123'
console.log(name1) // 123

2. 字符串字面量

type EventNames = 'click' | 'scroll' | 'mousemove';
// 参数event的值必须为上面三个其中一个
function handleEvent(e: Element, event: EventNames){
    // do something
}

3. 元组

let om: [string, number];
om[0] = 'Tom';

4. 枚举

4.1 普通枚举

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

4.2 常数枚举

常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员

const enum Directives {
    Up, Down, Left, Right
}

4.3 外部枚举

常出现在声明文件中

declare enum Directions {
    Up, Down, Left, Right
}

四. 类

1. TypeScirpt中类的用法

/** 
 * Note:
 * public、private、protected(受保护的)
 * 1. 使用private修饰的属性或方法,在子类也不允许访问
 * 2. 使用protected修饰,在子类中允许访问
 * 3. 当构造函数修饰为 private 时,该类不允许被继承或者实例化
 * 4. 当构造函数修饰为 protected 时,该类只允许被继承
 */

 class Animal {
    protected name;
    public constructor(name) {
        this.name = name;
    }
}

class Cat extends Animal {
    constructor(name) {
        super(name);
        console.log(this.name);
    }
}

2. 只读属性

readonly,只读属性关键字,只允许出现在属性声明或索引签名中

注意如果 readonly 和其他访问修饰符同时存在的话,需要写在其后面

class Animal2 {
    // public readonly name;
    public constructor(public readonly name) {
        this.name = name;
    }
}

3. 抽象类

/** 
 * Note: abstract 用于定义抽象类和其中的抽象方法
 * 抽象类不允许被实例化
 * 抽象类中的抽象方法必须被子类实现
 */
abstract class Animal3 {
    public name;
    public constructor(name) {
        this.name = name;
    }
    public abstract sayHi();
}

class Cat1 extends Animal3 {
    public sayHi() {
        console.log(`Meow, My name is ${this.name}`);
    }
}

let cat = new Cat1('Tom');

五. 类与接口

1. 实现(implements)

可以将不同类之间共有的特性提取成接口(interface),用implements关键字实现

// 报警器接口
interface Alarm {
    alert();
}
class Door {
}
// 安全门继承门的类 并实现报警器
class SecurityDoor extends Door implements Alarm {
    alert() {
        console.log('SecurityDoor alert');
    }
}

2. 接口可以继承接口

interface B extends interfaceA {}

3. 接口继承类

interface B extends classA {}

六. 泛型

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

1. 单个类型参数

// 使用T指代任意输入的类型, 输出则为Array<T>
function createArray<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray<string>(3, 'x'); // ['x', 'x', 'x']

2. 多个类型参数

// 定义泛型的时候,可以一次定义多个类型参数
function swap<A, S>(tuple: [A, S]): [S, A] {
    return [tuple[1], tuple[0]];
}
console.log(swap([7, 'seven']));

3. 泛型约束

// 比如让一个函数的参数和返回值必须拥有length方法时
interface Len {
    length: number;
}
function lenFunc<T extends Len>(arg: T): T {
    console.log(arg.length);
    return arg
}

4. 使用泛型接口

// 使用含有泛型的接口来定义函数的形状
interface CreateArrayFunc {
    <T>(length: number, value: T): Array<T>;
}

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

createArray2(3, 'x');

5. 泛型类

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

6. 为泛型指定默认类型

function con<T = string>(arg: T): T{
    return arg
}
发布了171 篇原创文章 · 获赞 246 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/weixin_42042680/article/details/103461932