TypeScript(二)基本类型

978 阅读7分钟

TypeScript中的基本类型

类型声明:

  • 类型声明是TS非常重要的一个特点;

  • 通过类型声明可以指定TS中变量(参数、形参)的类型;

  • 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错;

  • 简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值;

  • 语法:

    • let 变量: 类型;
      ​
      let 变量: 类型 = 值;
      ​
      function fn(参数: 类型, 参数: 类型): 类型{
        ...
      }
      

自动类型判断:

  • TS拥有自动的类型判断机制
  • 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
  • 所以如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明

类型:

类型例子描述
number1, -33, 2.5任意数字
string'hi', "hi", hi任意字符串
booleantrue、false布尔值true或false
字面量其本身限制变量的值就是该字面量的值
any*任意类型
unknown*类型安全的any
void空值(undefined)没有值(或undefined)
never没有值不能是任何值
object{name:'孙悟空'}任意的JS对象
array[1,2,3]任意JS数组
tuple[4,5]元祖,TS新增类型,固定长度数组
enumenum{A, B}枚举,TS中新增类型

1. number数字

TypeScriptJavaScript一样,所有的数字都是浮点数,并没有区分 intfloatdouble等类 型,所有的数字都是numbernumber类型支持十进制、十六进制等,以及 NaNInfinity等。

const decimalnumber = 6;
const binarynumber = 0b1010// 10
const hexnumber = 0xf00d// 61453
const octalnumber = 0o744;// 484
const bigbigint = 100n;// 表示一个bigint型

2. string字符串

使用string定义字符串类型的变量,支持常规的单引号和双引号,也支持ES6的模板字符串:

const namestring = 'axuebin'// axuebin
const descstring = `My name is ${name}`// My name is axuebin

3. boolean

let isDoneboolean = false;
function hello(isBetterCode: boolean) {
    // ...
    return isBetterCode ? 'good' : 'bad';
}
const isBetterCodeboolean = true;
hello(isBetterCode); // good

举例,下面这两行代码分别返回什么:

new Boolean('') == false
new Boolean(1) === true

所以,如果这样声明了一个表示布尔值的变量,编译是不会通过的:

const isBetterCodeboolean = new Boolean(1);
// Type 'Boolean' is not assignable to type 'boolean'.
// 'boolean' is primitive, but 'Boolean' is a wrapper object. Prefer using
'boolean' when possible

因为 new Boolean 返回的是一个 Boolean 对象,而不是一个 boolean 值。

如果你想这样写,也都是可以的:

const isBetterCodeBoolean = new Boolean(1);
const isBetterCodeboolean = Boolean(1);

4. 字面量

也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围

let color'red' | 'blue' | 'black';
let num1 | 2 | 3 | 4 | 5;

5. void空

void 0;// undefined

TypeScript中,void表示任何返回值的函数:

function hello(): void {
    console.log('hello typescript');
}

6. never

function error(message: string): never {
     throw new Error(message);
}

7. null和undefined空

const uundefined = undefined// undefined
const nnull = null// null

需要注意的是:

undefined 类型的变量只能被赋值为undefinednull类型的变量只能被赋值为null

不过你可以把undefinednull类型的变量赋给 void 类型的变量

8. object(没啥用)

const objobject = {};

9. any任意值

无法确定类型的变量,我们就需要any这个类型。any类型的变量可以被赋予任意类型的值:

let numberany = 'one';
number = 1//1
const meany = 'axuebin';
console.log(me.name); // undefined 不会报错

这样是不会报错的。

当然,如果在编程阶段能够确定类型的话,尽量还是能够明确指定类型。

声明变量(没赋值)的时候,如果未指定类型,那么该变量会被识别为 any 类型,比如:

let number// 相当于 let number: any;
number = 1//1

需要注意的是,没赋值。如果声明变量的时候同时赋值了,就会进行类型推论。

10.类型推论

声明变量的时候,如果对变量进行赋值,如果该变量没有明确地指定类型, TypeScript 会推测出一个 类型。

let number = 'one'// 相当于 let number: string = 'one';
number = 1// Type '1' is not assignable to type 'string'.

如果只声明没有赋值,就是any

11. unknown

let notSureunknown = 4;
notSure = 'hello';
any 和 unknown区别
let valueunknownlet value1unknown = value   // OK
let value2any = value       // OKlet value3boolean = value   // Error
let value4number = value    // Error
let value5string = value    // Error
let value6object = value    // Error
let value7any[] = value     // Error

unknown 类型只能分配给 any 类型和 unknown 类型本身。

现在继续尝试:

let valueunknown
​
value.foo.bar  // Error
value.trim()   // Error
value()        // Error
new value()    // Error
value[0][1]    // Error

unknown 类型在被确定为某个类型之前,不能被进行诸如函数执行、实例化等操作,一定程度上对类型进行了保护。

在那些将取得任意值,但不知道具体类型的地方使用 unknown,而非 any

12. array数组

TypeScript中,数组通过 [类型 + 方括号] 来定义:

const mestring[] = ['jack''27']; // 定义一个都是 string 的数组
const countsnumber[] = [1234]; // 定义一个都是 number 的数组
// error
const mestring[] = ['jack'27]; // Type 'number' is not assignable to type 'string'.
counts.push('5'); // Argument of type '"5"' is not assignable to parameter of type 'number'.

还有一种方式是使用泛型:

const countsArray<number> = [1234]; // 使用泛型定义一个都是 number 的数组

关于泛型,后面会仔细说明,现在就知道有这么个东西。

如果对数组中的类型不确定,比较常见的做法就是使用any

const listany[] = ['axuebin'27true];

13. tuple元组

还有一种特殊的情况,如果我们需要定义一个已知元素数量和类型的数组,但是各个元素的类型不相同,可以使用 tuple元组来定义:

const me: [stringnumberboolean] = ['axuebin'27true];

当我们想要在这个数组 push 一个新元素时,会提示 (string | number | boolean) ,这是表示元组 额外增加的元素可以是之前定义的类型中的任意一种类型。 (string | number | boolean) 称作联合类型

14. eunm枚举

枚举是 TS 对 JS 标准数据类型的补充,Java/c等语言都有枚举数据类型,在 TypeScript 里可以这样定义一个枚举:

enum Animal {
    Cat,
    Dog,
    Mouse,
}
const catAnimal = Animal.Cat// 0
const dogAnimal = Animal.Dog//1

既然是 JavaScript 没有的,我们就需要知道一个枚举最终会被编译成什么样的 JavaScript 代码:

"use strict";
var Animal;
(function(Animal) {
Animal[Animal["Cat"] = 0] = "Cat";
Animal[Animal["Dog"] = 1] = "Dog";
Animal[Animal["Mouse"] = 2] = "Mouse";
})(Animal || (Animal = {}));
const cat = Animal.Cat// 0
const dog = Animal.Dog// 1

很容易看出,Animal 在 JavaScript中是变成了一个object,并且执行了以下代码:

Animal["Cat"] = 0// 赋值运算符会返回被赋予的值,所以返回0
Animal[0] = "Cat";
// 省略 ...
// 最终的 Animal 是这样的
{
    0"Cat",
    1"Dog,
    2: "Mouse",
    Cat: 0,
    Dog: 1,
    Mouse: 2,
}

枚举最终会编译成双向键值对对象

enum Color {
     Red,
     Green,
     Blue,
}
let cColor = Color.Green;
​
enum Color {
     Red = 1,
     Green,
     Blue,
}
let cColor = Color.Green;
​
enum Color {
     Red = 1,
     Green = 2,
     Blue = 4,
}
let cColor = Color.Green;

字符串枚举,即一一映射

enum Person {
    jack = '杰克',
    anna = '安娜'
}

15. Symbol

每个Symbol()方法返回的值都是唯一的。

const sym1symbol = Symbol()
const sym2symbol = Symbol('foo')
const sym3symbol = Symbol('foo')
console.log(sym2 === sym3) // false

Symbol() 作为构造函数是不完整的:

const sym = new Symbol() // TypeError

这种语法会报错,是因为从 ECMAScript 6 开始围绕原始数据类型创建一个显式包装器对象已不再被支持,但因历史遗留原因, new Boolean()new String() 以及 new Number() 仍可被创建:

const symbol = new Symbol()   // TypeError
const bigint = new BigInt()   // TypeErrorconst number = new Number()   // OK
const boolean = new Boolean() // OK
const string = new String()   // OK
使用场景
  1. 当一个对象有较多属性时(往往分布在不同文件中由模块组合而成),很容易将某个属性名覆盖掉,使用 Symbol 值可以避免这一现象,比如 vue-router 中的 name 属性。

    // a.js 文件
    export const aRouter = {
     path'/index',
     nameSymbol('index'),
     componentIndex
    },
    ​
    // b.js 文件export const bRouter = {
     path'/home',
     nameSymbol('index'), // 不重复
     componentHome
    },
    ​
    // routes.js 文件
    import { aRouter } from './a.js'
    import { bRouter } from './b.js'const routes = [
     aRouter,
     bRouter
    ]
    
  2. 模拟类的私有方法

    const permissionsymbol = Symbol('permission')
    ​
    class Auth {
        [permission]() {
           // do something
        }
    }
    

    这种情况通过类的实例是无法取到该方法,模拟类的私有方法。

    但是,TypeScript 是可以使用 private 关键字的,所以这种方法可以在 JavaScript 中使用。

  3. 判断是否可以用 for...of 迭代

    if (Symbol.iterator in iterable) {
       for(let n of iterable) {
         console.log(n)
      }
    }
    
  4. Symbol.prototype.description

    const symsymbol = Symbol('imooc')
    ​
    console.log(sym);               // Symbol(imooc)
    console.log(sym.toString());    // Symbol(imooc)
    console.log(sym.description);   // imooc