ts简介

什么是typescript

  • GitHub:TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
  • TypeScript:TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
  • TypeScript是JavaScript的超集,它带有类型并编译出干净的JavaScript代码.
  • TypeScript支持JavaScript的所有特性,并跟随ECMAScript的标准发展,因此支持ES6,ES7,ES8等语法标准
  • 除了类型约束,TypeScript还增加了一些语法扩展,例如枚举类型,元组类型等
  • TypeScript总是与ES标准保持同步甚至领先,最终编译成JavaScript代码,不存在兼容性问题,不需要依赖Babel等工具.


搭建TypeScript运行环境

使用ts-node库为TypeScript的运行提供运行环境,这样就可以通过Node.js命令直接执行TypeScript代码,无须手动编译成JavaScript代码,当然还可以通过webpack搭建TypeScript运行环境,这里我们是通过ts-node来测试的

TypeScript-ts的数据类型_typescript


TypeScript的数据类型

any类型

在某些情况下,我们难以确定变量的类型,且类型可以会发生变化,这时可以使用any类型,any类型具有以下特点:

  • 可以对any类型的变量进行任何操作,包括获取不存在的属性和方法
  • 可以为一个any类型的变量赋任意值,如数字或字符串的值
/**
 * 数组工具类,从AS移值过来
 */
export class ArrayUtils {
    /**
     * 判断数据是否为空
     */
    static isEmpty(value: Array<any>): boolean{
        return value === undefined || value == null || value.length === 0;
    }

    /**
     * 是否包含
     */
    static contains(data: Array<any>, target: any): Boolean {
        return !ArrayUtils.isEmpty(data) && data.indexOf(target) !== -1;
    }
}

console.log(ArrayUtils.contains([1, 2, 3], 3))

unknown类型

unknown是TypeScript中比较特殊的一种数据类型,用于描述类型不确定的变量.

function foo(){return "abc"}
function bar(){return 123}
// 1.unknown类型:只能赋值给any和unknown
// 2.any类型:可以赋值给任意类型
let flag = true
let result: unknown // 可接收类型
if (flag){
    result = foo() //接收string类型
}else{
    result=bar() //接收number类型
}
console.log(result);

// 下面两个赋值会报错,因为unknown类型只能赋值给any和unknown类型
// let message: string = result
// let num: number = result


void类型

void通常用于指定一个函数没有返回值,因此其返回值类型为void,如果函数返回void类型,则可以将null或undefined赋值给该函数,即函数可以返回null或undefined.

/**
 * 数组工具类,从AS移值过来
 */
export class ArrayUtils {
   /**
    * 将一个对象随机位置放在数组中
    */
   static insertRandom(data: Array<any>, target: any): void {
        var index = Math.floor(Math.random() * data.length);
        data.splice(index, 0, target);
        console.log(data)
   }
}
ArrayUtils.insertRandom(["呵呵", "嘻嘻", 1], "你是mm还是gg")


never类型

never类型表示永远不会有返回值的类型

  • 如果一个函数陷入死循环活着抛出一个异常,那么这个函数将不会有任何返回值
  • 如果一个函数确实没有返回值,那么使用void类型活着其他类型作为返回值类型不适合,这时就可以使用never类型.
export {}
function loopFoo(): never { //never类型,说明该函数不会返回任何内容
    while (true) {
        console.log("123")
    }
}

function handleMessage(message: number|string){
    switch (typeof(message)){
        case 'string':
            console.log('foo');
            break
        case 'number':
            console.log('bar');
            break
        default:
            //当执行这里的代码时,将message赋值给never类型的check会报错
            //这样就可以保证,当修改参数的类型后,一旦出现case没有处理到的情况,就会报错
            //例如,参数增加对boolean类型的支持时,必须在case中编写对应的处理情况,否则报错
            const check: never = message;
    }
}


tuple类型

元组类型,即多个元组的组合,许多编程语法中有这种数据类型,例如Python和Swift等.

以下是元组和数组类型的区别:

  • 数组中通常建议只存放相同类型的元素,不推荐存放不同类型的元素.
  • 元组中每个元素都有自己独特的类型,对于通过索引值获取到的值,可以确定其对应的类型
function useState(state: any){
    let currentState = state
    const changeState = (newState: any) => {
        currentState = newState
    }
    const tuple: [any, (newState: any) => void] = [currentState, changeState]
    return tuple
}
const [counter, setCounter] = useState(10); //解构出来的counter, setCounter是有类型提示的
console.log(counter, setCounter);
export {}


TypeScript类型的补充

函数的参数和返回值

函数是javascript中非常重要的组成部分,TypeScript允许我们指定函数的参数和返回值的类型.

export {}
function sum(num1: number, num2: number) {
    console.log(num1 + num2);
    return num1 + num2;
}
sum(1, 2)
// 当调用sum函数,如果传入的参数类型或数量不正确,就会报错

// 为返回值加上类型注释(): number
function sum1(num1: number, num2: number): number{
    console.log(num1 + num2);
    return num1 + num2;
}

sum1(1, 2)
// 在typescript中,返回值的类型注解和变量的类型注解相似,通常不需要显式地指定返回类型
// typescript会根据函数内部的return语句推断函数的返回类型,不过,为了增加代码的可读性,有些第三方库会显式指定函数的返回类型.

对象类型

如果希望限定一个函数接收的参数类型为对象类型,可以用对象类型作为参数

// 为参数point指定对象类型 {x: number, y: number}
function printPoint(point: {x: number, y: number}){
    console.log(point.x);
    console.log(point.y);
}
printPoint({x: 200, y: 100})
// 这里我们使用一个对象{x: 200, y: 100}作为类型
// 可以向对象添加属性,并告知typescript该属性的类型.
// 属性之间可以使用,或;分隔,最后一个分隔符是可选的
// 每个属性的类型也是可选的,如果不指定,那么默认为any类型.

// 在对象类型中,我们可以通过在属性名后面添加(?)的方式来指定某些属性为可选属性
// 为参数point指定对象类型: {x: number, y: number, z?: number}
function printPoint1(point: {x: number, y: number, z?: number}){
    console.log(point.x);
    console.log(point.y);
    console.log(point.z);
}
printPoint1({x: 123, y: 321})
printPoint1({x: 123, y:321, z:231})
export {}


联合类型

typescript的类型系统允许我们使用多种运算符,从现有类型中构建新类型

  • 联合类型由两个或多个其他类型组成
  • 表示该类型可以是这些类型中的任何一个值
  • 联合类型中的每个类型被称为联合成员

比如我定义了一个接口LogType,LogType有一个key属性可以为number或string类型,并且这个key属性为可选属性

export interface LogType {
    key?: number | string,
    name?: string,
    status?: 'start' | 'stop' | 'success' | 'failed' | 'error',
    message?: string,
    data?: string[],
}


类型别名

interface Plat {
    id?: number;
    platformId?: number;
    name?: string;
    shortName?: string;
    domain?: string;
    locale?: string;
    whiteList?: string[];
    main_version_id?: number;
    xlsFix?: string;
    operator_id?: number;
    operatorId?: number;
    operator_name?: string;
    game_id?: number;
    game_name?: string;
    config_file_name?: string;
}

type PlatformSelectGroupType = { name?: string, key?: number, id?: number, platformList?: Plat[] }
let Platform: PlatformSelectGroupType = {}
console.log(typeof  Platform)

export type ThemeType = 'filled' | 'outlined' | 'twoTone';
const fillTester = /-fill$/;
const outlineTester = /-o$/;
const twoToneTester = /-twotone$/;

export function getThemeFromTypeName(type: string): ThemeType | null {
    let result: ThemeType | null = null;
    if (fillTester.test(type)) {
        result = 'filled';
    } else if (outlineTester.test(type)) {
        result = 'outlined';
    } else if (twoToneTester.test(type)) {
        result = 'twoTone';
    }
    return result;
}

console.log(getThemeFromTypeName('icon-o'))

分别使用类型别名申请自定义类型PlatformSelectGroupType和ThemeType


类型断言

类型断言as

有时TypeScript无法获取具体的类型信息,这时就需要用到类型断言,比较常见的话定义一个枚举类型,申明变量的时候使用as断言断言为这个枚举类型

export {}
type RowSelectionType = 'checkbox' | 'radio';
let type = "checkbox" as RowSelectionType;
console.log(type);


非空类型断言

在javascript中经常使用if语句进行非空判断,而在typescript中,除了if语句,还可以使用非空类型断言进行非空判断

/**
 * 数组工具类,从AS移植过来
 */
export class ArrayUtils {
    /**
         * 比较两个数组的值是否一致
         * 注意传入的数据需要带有id字段
         * @param arr1 数组1
         * @param arr2 数组2
         */
    static checkArrayIsSame = (arr1: any[], arr2: any[]) => {
        // 首先会判断两个数组的长度,长度不一致,那值也不一致
        if (arr1?.length !== arr2?.length) {
            return false;
        }
        // 根据每个值的id字段进行比较
        for (let i = 0; i < arr1.length; i++) {
            if (arr1[i].id !== arr2[i].id) {
                return false;
            }
        }
        return true;
    }
}

console.log(ArrayUtils.checkArrayIsSame([1, 2, 3], [1, 2]));

上面的示例中我们使用了可选链,arr1?.length, arr2?.length相当于当arr1和arr2不为空时才会去比较它们的长度


!!操作符

!!操作符可以将一个其他类型的元素转换成boolean类型,类似于Boolean(变量)这种函数转换的方式.

比如需要对不同端设备进行适配

const ua = window.navigator.userAgent;
const iOS = !!ua.match(/iPhone/i);
const webkit = !!ua.match(/WebKit/i);
const iOSSafari = iOS && webkit && !ua.match(/CriOS/i);

ua获取 用户代理, iOS判断是否为iPhone设备,为iPhone则iOS为true,webkit 设备代理为Webkit则webkit为true,下面iOSSafari判断是否为 iOS 设备上的 Safari 浏览器,是的话则iOSSafari为true,后面就可以拿iOSSafari这个变量进行判断做适配动作


??操作符

??操作符是es11新增的空值合并操作符,用于判断一个值是否为null或undefined,具体来说,当左侧操作数为null或undefined时,返回右侧操作数,否则返回左侧操作数,该操作符可以简化代码,并提高代码的可读性

let message: string|null = 'Hello HarmonyOS'
// 1.以前的方式是使用三元运算符判空,赋默认值(会判断null, undefined, false为假)
const content1 = message ? message: "你好啊,李银河!";
// 2.使用||操作符判空,赋默认值(会判断null, undefined, false为假)
const content2 = message || "你好啊,李银河2!";
// 3.使用??操作符判空,则赋默认值(会判断null, undefined, false为假)
const content3 = message ?? "你好啊,李银河3!";

console.log(content3);
export {}


字面量类型

在typescript中,除了上述类型,还可以使用字面量类型

// "Hello World"也可作为一种类型,叫做字面量类型
let message: "Hello World" = "Hello World"
// message = "coder" 报错不能将类型“"coder"”分配给类型“"Hello World"”

// 要体现字面量类型的意义,必须结合联合类型
type Alignment = 'left' | 'right' | 'center'
let align: Alignment = 'left' // ok
// let align2: Alignment = 'bottom' // 报错 不能将类型“"bottom"”分配给类型“Alignment”。


类型缩小

在typescript中,缩小类型的过程被称为类型缩小,我们可以使用类似typeof padding === "number" 的条件语句改变typescript的执行路径,在特定的执行路径中,可以缩小变量的类型,使其比声明时更为精准

常见的类型保护如下:

  • typeof: 如typeof padding === "number"
  • 平等缩小如 ===, !=, switch
  • instanceof: 如d instanceof Date
  • in: 如'name' in {name: "coder"}

typeof

javascript支持typeof运算符,可以使用该运算符来检查值的类型,在typescript中可以通过检查值的类型来缩小不同分支中的类型,这种检查值的类型称为类型保护

export class Utils {
    /**
     * 判断属性类型是否为方法
     * @param obj 方法属性
     */
    static isFunction(obj: any): obj is Function {
        // typeof用于判断基本数据类型
        return typeof obj === "function";
    }

    /**
     * 判断属性类型是否为对象
     * @param obj
     */
    static isObject(obj: any) {
        return Object.prototype.toString.call(obj) == "[object, Object]";
    }

    /**
     * 判断变量是否为空
     * @param value
     */
    static isEmpty(value: any): boolean {
        return value === undefined || value === null;
    }


    /**
     * 判断变量是否有值
     * @param value
     */
    static hasValue(value: any): boolean {
        return !Utils.isEmpty(value);
    }

    /**
     * 判断属性类型是否为数值型
     * @param value
     */
    static isNumber(value: number): value is number {
        return Utils.hasValue(value) && typeof value === 'number'
    }

    /**
     * 判断属性类型是否为逻辑型
     * @param value
     */
    static isBoolean(value: boolean): value is boolean {
        return Utils.hasValue(value) && typeof value === 'boolean';
    }
}


平等缩小

可以使用switch, ===  !==   !=等运算符来表达相等性,进而实现类型缩小,axios请求工具封装代码示例

export class Utils {
    static isString(value: string): value is string {
        return Object.prototype.toString.call(value) === "[object String]";
    }
}

import {createBrowserHistory} from 'history';

const history = createBrowserHistory();
// response处理
function handleFailedResponse(response) {
    // 反构请求的状态信息
    // status 状态码
    // statusText 状态文本
    const {status, statusText} = response;
    switch (status) {
        case 401:
            // 清除本地存储
            localStorage.removeItem('token');
            response.data.msg = 401;
            history.push('/', {from: history.location});
            break;
        default:
            if (!Utils.isString(response.data)) {
                response.data.msg = "请求失败: " + status + " " + statusText;
            }
            break;
    }
    return Promise.reject(response);
}

次处使用case对响应状态码进行判断,如果是401的话则清除缓存,reponse data msg属性等于401 返回主页, 否则 reponse data msg属性等于其他状态码加状态文本


instanceof

javascript中有一个instanceof运算符,用于检查一个值是否为另外一个值的实例

export {}
class Student {
    studying() {}
}

class Teacher {
    teaching() {}
}

function work(p: Student | Teacher) {
    // 判断p是否为Student类型的实例还是为Teacher类型的实例
    if (p instanceof Student) {
        p.studying()
    }else{
        p.teaching()
    }
}

const stu = new Student()
work(stu)

可以看到,在work函数中通过判断变量p是否为Student类型的实例,将联合类型的p缩小为更具体的Student类型


in

javascript中有一个in运算符,用于判断对象是否具体指定名称的属性,如果指定属性存在于该对象或其他原型链中,那么in运算符将返回true,示例我之前写的一个获取机器可部署数量的方法发起getHostList请求,拿到response,判断当response返回对象有data属性,并且data.data属性值为一个数组才会执行下面的统计操作

TypeScript-ts的数据类型_数据类型_02