1.any和unkown的区别

  • any表示任意类型, 可以被任何类型分配,也可以分配给任何类型
  • unkwon表示未知类型, 可以被任何类型分配,不能分配给任何类型
  • 首先看any类型
  • // 1. 把any类型分配给其他类型
    let val:any
    let val_any:any = val;
    let val_unknown:unknown = val;
    let val_void:void = val;
    let val_undefined:undefined = val;
    let val_null:null = val;
    let val_number:number = val;
    let val_string:string = val;
    let val_boolean:boolean = val;
    // 报错:不能将类型“any”分配给类型“never”
    // let val_never:never = val;
    // 2.把其他类型分配给1any
    val = '';
    val = 1;
    val = true;
    val = null;
    val = undefined;
    // 报错:“unknown”仅表示类型,但在此处却作为值使用
    // val = unknown;
    // 报错:“never”仅表示类型,但在此处却作为值使用
    // val = never;
    // 报错:“any”仅表示类型,但在此处却作为值使用
    // val = any;
    // 报错:应为表达式
    // val = void;
    
  • 然后看看unknown类型
  • // 1.把unknown类型分配给其他类型
    let val: unknown;
    let val_any:any = val;
    let val__unknown:unknown = val;
    // 报错:不能将类型“unknown”分配给类型“string”
    let val_string:string = val;
    // 报错:不能将类型“unknown”分配给类型“number”
    let val_number:number = val;
    // 报错:不能将类型“unknown”分配给类型“boolean”
    let val_boolean:boolean = val;
    // 报错:不能将类型“unknown”分配给类型“null”
    let val_null:null = val;
    // 报错:不能将类型“unknown”分配给类型“undefined”
    let val_undefined:undefined = val;
    // 2.把其他类型分配给unknown类型
    val = '';
    val = 0;
    val = true;
    val = undefined;
    val = null;
    // 和any一样,报错
    val = void;
    val = any;
    val = unknown;
    val = never;
    
  • 代码规范,any虽然可以代表任意类型,但是能不用就不要用,这是默认的代码规范问题,不要用成anyscript!
  • 与any任意类型相比,因为unknown是未知类型,所以只能进行!!,!,?,typeof,instanceof等有限操作
  • 2. 数组和元组的区别

  • 如果数组的类型在[]前面,那么表示该数组全部都是该类型
  • 如果数组的类型在[]内部(严格限制类型和长度的元组),那么表示该数组的第x个元素是该类型
  • 首先,数组的类型在[]前面
  •     // 此时表示数组内部都是数字类型
        // let arr:number[] = [1,2,3];
        let arr:(number | string)[] = ['s',3,'a'];
        let arr:any[] = ['a',2,true];
    
  • 此时来看看数组的类型在[]内部的用法,此时就是元组
  •     // 报错:不能将类型“[number, number, number]”分配给类型“[number]”。源具有 3 个元素,但目标仅允许 1 个
        // let arr:[number] = [2,3,4];
        let arr:[number] = [2]; // 这个时候才是对的!
        // 表示多种类型的数组,但是严格限制长度和类型必须对照
        let arr:[string,number] = ['a',1];
        // 报错:不能将类型“string”分配给类型“number”
        // let arr:[string,number] = [1,'d'];
        // any元组也需要规定元素数量
        let arr:[any,any,any] = ['s',2,true];
    
  • 其实[string,boolean]这种声明形式指的是元组,也就是一个已知元素数量和类型的数组
  • 3.索引签名和工具类型Record的区别

  • 其实Record工具类型的本质就是索引签名,不同之处只是用法,仅仅需要继承就可以了,不需要再写一遍
  • 索引签名的用法
  • interface inf{
        name:string;
        age:number;
        [k:string]:any;
    let obj:inf = {
        name:'yiye',
        age:33,
        city:'foshan'
    
  • Record工具类型的用法(ts内置的工具类型)
  • interface inf extends Record<string,any>{
        name:string;
        age:number;
    let obj:inf = {
        name:'yiye',
        age:33,
        city:'foshan'
    
  • Record工具类型的.d.ts声明文件源码是:
  • type Record<K extends keyof any, T> = {
        [P in K]: T;
    
  • 所以用法就是继承这个工具类型,然后泛型参数1是属性类型,参数2是属性值的类型
  • 4.interface和type的区别

  • 如果在开发一个包或者要被继承,那么使用接口interface
  • 如果要定义基础数据类型或者进行类型运算,那么使用类型别名type
  • 不同点1:interface可以进行声明合并,type不可以
  • // 1.interface同名接口会自动进行声明合并
    interface union{
        name:string;
    interface union{
        age:number;
    let u = {} as union;
    // undefined
    console.log(u.name);
    // undefined
    console.log(u.age);
    // 但是使用其他属性,不会undefined,会报错:类型“union”上不存在属性“list”
    console.log(u.list);
    // 2.type类型别名不可以进行声明合并
    // 报错:标识符“type_a”重复
    // type type_a = number;
    // type type_a = string;
    
  • 不同点2:type可以直接进行赋值运算,而interface不可以,必须先继承
  • // 1.type可以进行类型运算(只能把type赋值给type,不能把type赋值给其他类型变量)
    type type_a = number;
    type type_sum = type_a | string;
    // 2. interface不可以,必须要通过继承
    interface inf_a{
        name:string;
    // “inf_a”仅表示类型,但在此处却作为值使用
    // interface inf_a = inf_a;
    // 正确做法是
    interface inf_b extends inf_a{
        age:number;
    let inf  = {} as inf_b;
    // undefined undefined
    console.log(inf.age,inf.name);
    
  • 不同点3:interface只可以用于对象和函数;type则可以用于对象,函数,基础类型,数组,元组
  • // 1.接口
    // 对象
    interface obj{
        name:string;
    // 函数
    interface func{
        (x:string): number;
    // 2.类型别名type
    // 对象
    type type_obj = {name:string};
    // 函数
    type type_func = (x:string) => string
    // 基础类型
    type type_boolean = true;
    type type_null = null;
    // 联合类型
    type type_union = string | number;
    // 数组
    type type_arr = number[];
    // 元组
    type type_tuple = [number,string];
    

    5.enum和const enum

  • enum可以进行反向查找,所以遍历得到的长度是预计长度的两倍
  • const enum不可以进行反向查找,所以得到的是预计长度
  • // 1. enum
    enum REVERSE{
    console.log(REVERSE.OK)
    // OK
    console.log(REVERSE[0])
    // OK
    console.log(REVERSE[1])
    // undefined,虽然是undefined,但是不会报错!
    console.log(REVERSE[10])
    // 遍历,得到枚举的值和反向查找的值
    // of不可以,警告需要有[Symbol.iterator]方法
    for(let item in REVERSE){
        // 0 1 OK NO
        console.log(item);
    // 2. const enum
    const enum ONE{
    console.log(ONE.OK)
    // 报错:只有使用字符串文本才能访问常数枚举成员。
    // console.log(ONE[0]);
    // 遍历
    // 报错:"const" 枚举仅可在属性、索引访问表达式、导入声明的右侧、导出分配或类型查询中使用。
    /* for(let item in ONE){
    

    1. 类型键入

    type User = {
        outer:string;
        // 内部使用一个数组
        innerList:{
            innerName:string
    // (property) outer: string
    type userOut = User['outer'];
    /* 属性数组
    (property) innerList: {
        innerName: string;
    }[] */
    type userList = User['innerList'];
    // 类型键入,获取数组的一个项
    // number表示数组子项的类型是number
    type userListItem = userList[number];
    let item:userListItem = {
        innerName:'yiye'
    // { innerName: 'yiye' }
    console.log(item)
    

    2 装饰器

    function fun() {
        return function(target: any, key: string, descriptor: PropertyDescriptor) {
            console.log(target); // 该装饰器所在的类或函数  any: 类
            console.log(key); // 装饰器应用的变量名 string : getDecorator
            console.log(descriptor); // 装饰应用的变量的descriptor属性
            // {writable: true, enumerable: false, configurable: true, value: ƒun}
    class A {
        @fun()
        getDecorator() {
            console.log('测试');
    let obj:A = new A();
    obj.getDecorator();
    

    3. typeof

  • typeof 关键字在 JS 中用来获取变量的类型,运算结果是一个字符串(值)。而在 TS 中表示的是推算一个变量的类型
  • // 1.1 typeof变量,得到的是变量的类型
    let str_1 = 'hello'
    // string
    console.log(typeof str_1);
    type type_1 = typeof str_1;
    let obj_1:type_1 = 'dd';
    // dd
    console.log(obj_1)
    // 1.2 typeof常量,得到的是常量的值
    const str_2 = 'abc'
    // 虽然打印得到的是string
    console.log(typeof str_2);
    // 但是通过type赋值为类型
    type type_2 = typeof str_2;
    // 此时会报错
    // 报错:不能将类型“"typeof常量得到的类型是常量的值"”分配给类型“"abc"”
    // let obj_2:type_2 = 'typeof常量得到的类型是常量的值';
    // 这个时候才正确
    let obj_3:type_2 = 'abc';
    // 1.3 typeof对象
    interface person{
        name:string,
        age:number
    let obj:person = {
        name:'yiye',
        age:11
    // object
    console.log(typeof obj)
    // 本质上就是:type type_obj = person
    type type_obj=typeof obj;
    // 1.4 typeof函数
    function foo(key:string){
        return key;
    // type type_func = (key: string) => string
    type type_func = typeof foo;
    

    4.keyof

  • keyof关键字用来获取一个对象类型的所有key类型
  • type type_1 = {
        id:number,
        name:string
    // keyof type_1得到 "id" | "name"
    // 因为作为变量key_1的类型,所以key_1只能被赋值为"id" | "name"
    let key_1: keyof type_1 = 'id'
    // let key_1: keyof type_1 = 'name'
    // 报错:不能将类型“"a"”分配给类型“"id" | "name"”
    // let key_1: keyof type_1 = 'a'
    console.log(key_1);
    // keyof应用到泛型
    // 表示传递的第一个值是对象,第二个值是对象的属性
    function foo<T extends Object, K extends keyof T>(obj:T,key:K){
        console.log(obj[key]);
    interface key{
        name:string,
        age:number
    let obj:key = {
        name:'yiye',
        age:11
    // yiye
    foo(obj,'name');
    // 11
    foo(obj,'age');
    // 报错:类型“"a"”的参数不能赋给类型“"name" | "age"”的参数
    // foo(obj,'a');
    

    本文使用 mdnice 排版

    分类:
    前端
    标签: