• TS类型全解


     使用TypeScript开发的程序更安全,常见的错误都能检查出来。TS能让程序员事半功倍。而原因在于TS的“类型安全”(借助类型避免程序做无效的事情)。

    图 运行程序的过程

    但是TS不会直接编译成字节码,而是编译成JavaScript代码。TS编译器生产AST后,先对代码做类型检查,然后再编译成JavaScript代码。

    图 TS运行程序的过程

    1 类型

    类型是指一系列值及对其执行的操作。

    图 TS的类型层次结构

    TS具有自动推导类型的功能:

    let num1 = 1; // 推导为number类型

    我们可以不要显式的指明num1为number类型(let num1:number = 1),这是一种推荐的写法。

    1.1 unknown与any

    unknown

    表示任何值,但是TS会要求你再做检查,细化类型。

    any

    表示任何值,TS不会做检查,应尽量避免使用。

    表 unknown与 any的对比

    unknown类型的值可以比较(使用==、===、||、&&和?)、可以否定(使用!)及可以使用typeof和instanceof。

    1. let a: unknown = 30; //unknown
    2. let b = a === 123; // boolean
    3. let c = a + 10; //Error,Object is of type ‘unknown’
    4. if (typeof a ===number’) {
    5.   let d = a + 10; // number
    6. }

    unknown的用法如下:

    1)TS不会把任何值推导为unknown类型,必须显示注解。

    2)unknown类型的值是可以比较。

    3)操作时不能假定unknown类型的值为某种特定类型,必须先向TS证明这个值确实是某个类型。

    any 应尽量避免使用。在极少数情况下,any将发挥作用:

    1. let a: any = 66;
    2. let b: any = ['danger'];
    3. let c = a + b; // string 66danger 如果上面不显式指明为any类型,则会报编译错误

    1.2 boolean

    boolean类型有两个值:true和false。该类型的值可以比较(==、===、||、&&和?)、可以否定(!)。用法如下:

    1. let a = true; // boolean
    2. const b = true; // ture
    3. let c: boolean = false; // boolean
    4. let d: true = true; // true
    5. let e: true = false; // error Type false is not assignable to type true

    1.2.1 推导类型的四种方式

    1)让TS推导出值的类型为boolean(a)。

    2)让TS推导出值为某个具体的布尔值(b)。

    3)明确告诉TS,值的类型为boolean(c)。

    4)明确告诉TS,值为某个具体的类型值(d和e)。

    第四种情况,称为类型字面量。即仅表示一个

    1. let a: object = {
    2.     x: 'a'
    3. };
    4. a = {name:'212'};
    5. console.log(a); // {x:'212'}
    6. a = false; // error Type boolean is not assignable to type object
    7. a.name; // error,Property name does not exist on type object
    8. let b: Object = {
    9.     name: 'b'
    10. };
    11. b = true;
    12. b.name; // Property name does not exist on type Object

    值的类型。注意,这种情况下也仍需为变量赋值,否则变量为空。

    1.3 对象

    object

    接受所有引用类型,除基本类型(string、number、boolean、undefined和null)外,都可以赋值给它。

    Object

    是一个通用类型,可以被赋予任何类型的值。赋值以后能改变类型。

    {}

    Object的别名。

    表 object、Object与{}

    这三种只能表示该值是一个JS对象,范围比较窄,尽量避免使用。

    1.3.1 对象字母量

    上面的a指定为object类型后,在引用属性name时提示并没有该字段。这时,我们可以采用让TS自行推导的方式:

    1. let a = {
    2.     name: 'hello'
    3. }; //类型为 {name: string}
    4. console.log(a.name); // hello

    这种声明对象类型的方式称为对象字面量句法(“这个东西的结构是这样的”)。可以让TS推导对象结构,也可以在花括号内明确描述:

    1. let a: {name: string} = {
    2.     name : 'a'
    3. };
    4. a = {
    5.     name: "b"
    6. };
    7. a = {
    8.     name: 'c',
    9.     age: 17 // error Type { name: string; age: number; } is not assignable to type { name: string; }
    10. }

    如果先声明变量,然后在初始化,TS将确保在使用该变量时已经明确为其赋值了。

    1.3.2 属性可选

    1. let a: {
    2.     att1: number,
    3.     att2?: string, //该属性可以没有
    4.     [key: number]: boolean // 可能有任意多个数字属性,其值为boolean类型。(key这个名字可以是任意的)
    5. }
    6. a = {att1: 1};
    7. a = {att1: 2, att2: 'hello'};
    8. a = {att1: 1, 1: true,2: false};

    上面[key:T]: U 句法称为索引签名,通过这种方式告诉TS,指定的对象可能有更多的键。键的类型为T,值的类型为U。其中T必须为number或string类型。key可以是任意名称。

    1.4 数组与元组

    TS支持两种注解数组类型的句法:T[]和Array。两者作用和性能无异。

    1. let arr: string[] = ["hello","TS"];
    2. let arr2: Array<string> = ["hello","TS"];
    3. let arr3: any[] = [1,"hello",false]; // 一般情况,数组应该保持同质,即类型一样

    any[]离开定义时所在的所用域后,TS将最终确定一个类型,不再扩张。

    1. function buildArr() {
    2.     let a = []; // any[]
    3.     a = [1,false];
    4.     return a;
    5. }
    6. let newArray = buildArr();
    7. newArray.push(2);
    8. newArray.push("hello"); // 运行时报错 Argument of type '"hello"' is not assignable to parameter of type 'number | boolean'

    1.4.1 元组

    元组是array的子类型。长度固定,各索引位的值具有固定的已知类型。与其他类型不同,声明元组时必须显式注解类型:

    let a: [string,number,boolean];

    元素也支持可选的元素(?表示可选)。也支持剩余元素,即为元组定义最小长度:

    1. let a: [string,boolean?];
    2. a = ["hello"];
    3. a = ['hello', false];
    4. let b: [boolean,...string[]];
    5. b = [true];
    6. b = [true,'hello'];

    1.4.2 只读数组和元组

    1. let a: readonly string[] = ["a","b","c"];
    2. a.concat("s");
    3. console.log(a.concat("s")); // [ 'a', 'b', 'c', 's' ]
    4. console.log(a); // ["a","b","c"];
    5. a.push("x"); // Property push does not exist on type readonly string[]

    若想更改只读数组,使用非变型方法,例如.concat和.slice。不能使用可边型方法,例如.push和.splice。

    1.5 其他类型

    处理较长的数字时,为了便于标识数字,建议使用数组分隔符:

    1. let a = 1_000_000
    2. let c : 1_233_344 = 1_233_344; //注意,这里对c一定要赋值,如果是:let c : 1_233_344,这样值为空

    null

    缺少值。

    undefined

    尚未赋值的变量。

    void

    没有return语句的函数。

    never

    永不返回的函数。

    表 TS中的空值

    1.5.1 枚举

    使用枚举极易导致安全问题,建议远离枚举。

    1)枚举可以分几次声明:

    1. enum Language {
    2.     Chinese,
    3.     English
    4. }
    5. enum Language {
    6.     Russian = 2 //此时必须为这个枚举指定一个与上面枚举值不同的值
    7. }
    8. console.log(Language[1]); // English
    9. console.log(Language.English); // 1
    10. // Language:
    11. // {
    12. //     '0': 'Chinese',
    13. //     '1': 'English',
    14. //     '2': 'Russian',
    15. //     Chinese: 0,
    16. //     English: 1,
    17. //     Russian: 2
    18. // }

    2)枚举值可以混用字符串和数字。(在枚举中,尽量不要使用数字,否则可能会置枚举于不安全的境地。)

    1. enum Language {
    2.     Chinese= 1,
    3.     English= 'e'
    4. }
    5. // { '1': 'Chinese', Chinese: 1, English: 'e' }

    3)为避免不安全的访问操作,可以通过const enum指定枚举的安全子集。来限制只能通过字符串来访问。

    1. enum Language {
    2.     Chinese= 1,
    3.     English= 'e'
    4. }
    5. console.log(Language[3]); // undefined 可以访问,这样操作不安全。
    6. const enum Language2 {
    7.     Chinese= 1,
    8.     English= 'e'
    9. }
    10. Language2[2]; //error const类型只能通过字符串类型访问,即Language2.Chinese

    2 语言特性

    2.1 类型别名 type

    可以使用变量声明(let、const)为值声明别名,类似的,可以为类型声明别名:

    type Age = number; // number的别名为Age

    这样可以减少重复输入复杂的类型及更清楚地表明变量的作用。

    别名具有以下特性:

    1)使用别名的地方都可以替换成源类型。

    2)同一个类型别名不能声明两次。

    3)别名采用块级作用域。内部的类型别名将掩盖外部的类型别名。

    1. type Age = 18;
    2. {
    3.     type Age = string;
    4. }
    5. type Age = boolean; // Duplicate identifier Age

    2.2 并集和交集

    1. type A = {name: string,age: number};
    2. type B = {name: string,file: boolean};
    3. type C = A | B;  // {name: string,age:number,file: boolean}
    4. type D = A & B; // {name: string}
  • 相关阅读:
    java项目之服装定制系统(ssm框架)
    VUE3 Router学习 第二章 导航守卫(全局前置、后置守卫)、路由元信息(meta)、过渡动效、滚动行为(scrollBehavior)
    【Nginx32】Nginx学习:随机索引、真实IP处理与来源处理模块
    vue--1.vue开发环境集成、基础指令、属性绑定
    MySQL中的SHOW FULL PROCESSLIST命令
    【C++ 学习】指针与函数与多维数组
    docker 安装 superset
    二锅头帮你整理CSS
    『力扣每日一题12』:只出现一次的数字
    CICD—Jenkins Gitlab自动化打包java到K8S
  • 原文地址:https://blog.csdn.net/qq_25308331/article/details/134544287