TS的基本类型检查

258 阅读5分钟

基本类型约束

TS是一个可选的静态的类型系统,没有必要一定使用ts规则

如何进行类型约束

仅需要在变量、函数的参数,函数的返回值位置加上:类型

简单的例子:

    function sum1(a:number , b:number) : number{
        return a + b;
    }
    const total: number = sum1(1,2);
  • 在js中sum函数可以被更改,如改成sum = 1,而在ts中,更改sum会报错,sum(1, 2) 明确知道引用的哪一个函数,则当选中sum使用后F2改变sum的函数名字时为add时, sum(1, 2)也会自动变成add(1, 2),非常方便

  • 自动推导,对于sum函数,当指定两个参数为number类型时,会自动推导出函数类型为number。 ts在很多场景中可以完成类型推导

  • 如何知道是否可以推导出类型

    image.png

    当变量出现三个点时,意思是类型为any,没有明确类型,书写代码时应注意

    any:表示任意类型,ts不进行类型检查

小技巧:如何区分数字字符串和数字,关键看怎么读? 如果按照数字的方式读,则为数字,否则为字符串。

源代码和编译结果的差异

编译结果没有类型约束信息。运行的时候没有ts代码,输出结果为:

    function sum1(a, b) {
        return a + b;
    }
    let total = sum1(1, 2);

基本类型

  • number: 数字
  • string: 字符串
  • boolean: 布尔
  • number[]: 数组
  • object: 对象
  • null和undefined

ts会根据类型智能提示相关方法,智能程度待议

  1. 为了加深对于ts严格类型检查的印象,现有判断是否为奇数的函数,出现以下报错,请问为什么

    image.png

    为什么会报错呢?

    ts有严格的类型检查,规定了函数类型为boolean,则必须返回truefalse

  2. 数组约束

    下面两种写法意思一样,意思是声明数字类型数组,需指定数组中的各元素类型

        let array1: number[];
        let array2: Array<number>;
    

    不要使用let array1: [];,后面在字面量类型中会提到

  3. null和undefined

    null和undefined可以赋值给其他类型,开发时会有隐患,如

        const str: string = undefined;
        str.toUppercase(); //因为str是string类型,会自动提示字符串方法,但是此情况会报错
    

    通过配置文件的"strictNullChecks": true可以获得更严格的类型检查,null和undefined只能赋值给自身

其他类型

  • 联合类型:多种类型各选其一 某些情况下,如用户姓名,可以为空。使用方法

        const name: string : undefined = 'string';
        //const name: string : undefined = undefined;
    

    此情况下使用字符串方法,智能提示消失,ts不清楚具体类型

    但是,此时就体现出ts智能提示恐怖之处,加入类型判断

        if(typeof name === 'string'){ 
        //类型保护
            name.toUppercase();//进入到判断中,ts已经知道name此时为string类型
        }
    

    类型保护:当对某个变量进行类型判断后,在判断的语句块中便可以判断它的确切类型,typeof可以触发类型保护,但是只能触发js中基本类型的类型保护,如果是object等复杂类型则不能触发。 配合类型保护进行判断

  • void类型:通常用于约束函数返回值,表示该函数没有任何返回值

  • never类型:通常用于约束函数返回值,表示该函数永远不会结束

    ts会默认以下函数为void类型,实际上该函数应该为never类型

        function throwError(msg: string): never {
            throw new Error(msg);
        }
        function continueFunc(): never {
            while (true) {}
        }
    
  • 字面量类型:使用一个值来约束

        let gender: '男' | '女';
        let arr: []; //arr只能取值为空数组
        let stu: {
            name: string;
            age: number;
        }; //对象的字面量约束,一般不使用
    
  • 元组类型:一个固定长度的数组,并且数组中每一项类型确定

  • any类型: any类型可以绕过类型检查,因此可以赋值给任意类型(不推荐使用)。

类型别名

对一些已知的类型定义名称

    type 类型名 = ...

为什么会有类型别名

当我们需要一个对象数组时,更改对象属性时,修改的地方过多,代码不美观

    let user: {
        name: string
        age: number
        gender: '男' | '女'
    }
    
    function getUSer(): {
        name: string
        age: number
        gender: '男' | '女'
    }[] {
        return [];
    }

当使用类型别名

    type Gender = '男' | '女';
    type User = {
        name: string
        age: number
        gender: Gender
    };

    let user: User;
    function getUsers(g: Gender): User[] {
        return [];
    }

函数的相关约束

先从一个简单的例子入手,两个参数,都是数字则返回相乘,都是字符串则返回字符串拼接,否则报错。

    function combine(a: number | string, b: number | string): number | string {
        if (typeof a === 'number' && typeof b === 'number') {
            return a * b;
        } else if (typeof a === 'string' && typeof b === 'string') {
            return a + b;
        }
        throw new Error('a and b must be same');
    }
    const reslut = combine(3, 3); //此时result的类型信息丢失

result的类型信息丢失,按理说传入的都是数字类型,返回的也只能是数字类型,但是事实并非如此。result的信息丢失对后面书写代码带来不便。

  • 函数重载:在函数实现之前,对函数调用的多种情况进行声明。

        /**
         * return a * b
         * @param a 
         * @param b 
         */
        function combine(a: number, b: number): number;
        /**
         * return a + b
         * @param a 
         * @param b 
         */
        function combine(a: string, b: string): string;
        function combine(a: number | string, b: number | string): number | string {
            if (typeof a === 'number' && typeof b === 'number') {
                return a * b;
            } else if (typeof a === 'string' && typeof b === 'string') {
                return a + b;
            }
            throw new Error('a and b must be same');
        }
        const reslut = combine(3, 3); //此时combine只能传入相同类型的数据,否则报错
    
  • 可选参数:可以在某些参数名后加上?,表示可以选择,可选参数必须在参数末尾。当最后一个参数为默认值且使用时未传递,被认为可选参数。

    function sum(a:number , b:number , c?:number){
        if(c){
            return a + b +c ;
        }else {
            return a + b;
        }
    }
  • 默认参数
    function sum(a:number , b:number , c?:number){
        return a + b + c;
    }

点击进入扑克牌例子github