TypeScript 学习记录1——理解类型

文章目录

  • 1. 理解any、unknown、never和void
    • any
    • unknow
    • never
    • void
  • 2. Object、object 和 {}
    • Object
    • object
    • {}
  • 3. type 命令、 typeof 运算符和 keyof 运算符
    • type
    • typeof
    • keyof
  • 4. 数组与元组
    • 数组
      • 只读数组
    • 元祖
      • 只读元组
    • 5. interface 与 type 的异同
  • 参考资料

1. 理解any、unknown、never和void

any

any 类型表示没有任何限制,该类型的变量可以赋予任意类型的值
变量类型一旦设为any,TypeScript 实际上会关闭这个变量的类型检查。即使有明显的类型错误,只要句法正确,都不会报错。

应该尽量避免使用any类型,否则就失去了使用 TypeScript 的意义

unknow

与any含义相同,表示类型不确定,可能是任意类型,但有一些限制:

  • unknown类型的变量,不能直接赋值给其他类型的变量(除了any类型和unknown类型)
  • 不能直接调用unknown类型变量的方法和属性

never

never类型表示的是那些永不存在的值的类型

function fn(x:string|number) {
  if (typeof x === 'string') {
    // ...
  } else if (typeof x === 'number') {
    // ...
  } else {
    x; // never 类型
  }
}
never类型的一个重要特点是,可以赋值给任意其他类型
never类型是任何其他类型所共有的,TypeScript 把这种情况称为“底层类型”(bottom type)

void

某种程度上来说,void类型像是与any类型相反,它表示没有任何类型

声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null
当一个函数没有返回值时,你通常会见到其返回值类型是 void,而不是undefined类型。否则将报错

2. Object、object 和 {}

TypeScript 的对象类型也有大写Object和小写object两种

Object

除了undefined和null这两个值不能转为对象,其他任何值都可以赋值给Object类型

object

object类型代表 JavaScript 里面的狭义对象,即可以用字面量表示的对象
只包含对象、数组和函数,不包括原始类型的值

{}

空对象{}是Object类型的简写形式,所以使用Object时常常用空对象代替

无论是大写的Object类型,还是小写的object类型,都只包含 JavaScript 内置对象原生的属性和方法,用户自定义的属性和方法都不存在于这两个类型之中。

const o1:Object = { foo: 0 };
const o2:object = { foo: 0 };

o1.toString() // 正确
o1.foo // 报错

o2.toString() // 正确
o2.foo // 报错

3. type 命令、 typeof 运算符和 keyof 运算符

type

type命令用来定义一个类型的别名

  • 别名不允许重名
  • 别名的作用域是块级作用域
  • 别名支持使用表达式
  • type命令属于类型相关的代码,编译成 JavaScript 的时候,会被全部删除

typeof

TS 中 typeof 可以用来获取一个变量或对象的类型

当一个 interface 总有一个字面量初始值时,可以考虑如下写法以减少重复代码

TypeScript 学习记录1——理解类型_第1张图片

keyof

keyof 用于得到一个对象(TS类型)的公共属性的联合类型

keyof any 的结果为 string | number | symbol

keyof (A & B) <=> keyof A | keyof B

keyof (A | B) <=> keyof A & keyof B

4. 数组与元组

数组

TypeScript 数组有根本特征:所有成员的类型必须相同

如下图,x 为 `string | number`,而非 `number`

在这里插入图片描述

TypeScript 允许使用方括号读取数组成员的类型

type Names = string[];
type Name = Names[0]; // string

只读数组

数组类型前面加上readonly关键字即可声明只读数组
只读数组不可删除、修改、新增数组成员

只读数组是数组的父类型

注意,readonly关键字不能与数组的泛型写法一起使用
实际上,TypeScript 提供了两个专门的泛型,用来生成只读数组的类型

const arr:readonly Array<number> = [0, 1]; // 报错
const a1:ReadonlyArray<number> = [0, 1];
const a2:Readonly<number[]> = [0, 1];

const断言可声明只读数组

const arr = [0, 1] as const;

arr[0] = [2]; // 报错 

元祖

元组(tuple)是 TypeScript 特有的数据类型,表示成员类型可以自由设置的数组

  • 元组必须明确声明每个成员的类型,否则 TypeScript 会把一个值自动推断为数组
  • 元组成员的类型可以添加问号后缀(?),表示该成员是可选的(只可用于尾部成员)
  • 可(任意位置)使用扩展运算符(…),可以表示不限成员数量的元组
  • 元组可以通过方括号,读取成员类型

只读元组

与数组相同,只读元组是元组的父类型,只读元组不能替代元组

一旦扩展运算符使得元组的成员数量无法推断,TypeScript 内部就会把该元组当成数组处理

5. interface 与 type 的异同

interface 与 type 都可以表示对象类型,几乎所有的 interface 命令都可以改写为 type 命令。二者区别有如下几点:

  • type能够表示非对象类型,而interface只能表示对象类型(包括数组、函数等)
  • interface可以继承其他类型,type不支持继承(type定义的对象类型如果想要添加属性,只能使用&运算符,重新定义一个类型)
  • 同名interface会自动合并,同名type则会报错
  • interface不能包含属性映射(mapping),type可以
    interface Point {
      x: number;
      y: number;
    }
    
    // 正确
    type PointCopy1 = {
      [Key in keyof Point]: Point[Key];
    };
    
    // 报错
    interface PointCopy2 {
      [Key in keyof Point]: Point[Key];
    };
    
  • this关键字只能用于interface
  • type 可以扩展原始数据类型,interface 不行
  • interface无法表达某些复杂类型(比如交叉类型和联合类型),但是type可以

综上所述,如果有复杂的类型运算,那么没有其他选择只能使用type;一般情况下,interface灵活性比较高,便于扩充类型或自动合并,建议优先使用

参考资料

  • TypeScript官方文档
  • TypeScript 教程 - 网道
  • 重学TypeScript - 掘金
  • 一文看懂any,never,void和unknown的区别

你可能感兴趣的:(学习,typescript)