目录
类型声明
- 类型声明是TS非常重要的一个特点
- 通过类型声明可以指定TS中变量(参数、形参)的类型
- 指定类型后,当变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,反之报错
- 类型声明就是给变量设置了类型,使得变量只能存储某种类型的值
- 语法如下
let 变量名 : 类型 let 变量名 : 类型 = 值 function fn(参数: 类型,参数: 类型):类型{ ... }
自动类型判断
- TS拥有自动的类型判断机制
- 当对变量的声明和赋值同时进行时,TS编译器会自动判断变量类型
- 当变量声明和赋值同时进行时,可以省略掉类型声明
TS中变量的12种类型
类型 | 例子 | 描述 |
number | 2,66,-6 | 任意数字 |
string | "du","student" | 任意字符串 |
boolean | true/false | 布尔值true/false |
字面量 | 字面量的本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的any类型 |
void | 空值(undefined) | 没有值或undefined |
never | 没有值 | 不能是任何值 |
object | {name:"杜同学。"} | 任意的JS对象 |
arrray | [6,66,666] | 任意的JS数组 |
tuple | [66,666] | 元组,TS的新增类型,是一种固定长度的数组 |
enum | enum{A,B} | 枚举类型,TS中新增类型 |
null和undefined的注意点
默认情况下 null
和 undefined
是所有类型的子类型。 就是可以把 null
和 undefined
赋值给其他类型。
// null和undefined赋值给string
let str:string = "666";
str = null
str= undefined
// null和undefined赋值给number
let num:number = 666;
num = null
num= undefined
// null和undefined赋值给object
let obj:object ={};
obj = null
obj= undefined
// null和undefined赋值给boolean
let isDone: boolean = false;
isDone = null
isDone= undefined
如果我们在tsconfig.json指定了"strictNullChecks":true
,null
和 undefined
只能赋值给 void
和它们各自的类型。这里的tsconfig.json 是 TypeScript 项目的配置文件,在后续章节中会详细讲到。
any类型
在 TypeScript 中,任何类型都可以被归为 any 类型。如果是一个普通类型,在赋值过程中改变类型是不被允许的:
let n: string = 'Du';
n =666;
// TS2322: Type 'number' is not assignable to type 'string'.
如果是any类型,则该变量允许被赋值为任意类型。
let a: any = 666;
a = "Du";
a = false;
a = 66
a = undefined
a = null
a = []
a = {}
[变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型]
let something;
something = 'Du';
something = 666;
//上述代码段和下边的代码段是等价的
let something: any;
something = 'Du';
something = 666;
当一个指定类型的变量被赋值为any类型后,指定类型的变量也失去了变量检查:
let n:any = 666
let str:string = "du"
//这里对string类型的str赋值any类型的n的值 666
str = n //ok 这里不会报错,而且string类型的str的值会变为number类型的666
console.log(str) // 666
any表示任意类型,一个变量设置了any类型后就相当于关闭了TS的类型检测,就无法使用 TypeScript 提供的大量的保护机制。请记住,any是魔鬼,使用了any和Js的变量书写就没有了区别,
尽量不要使用any。
为了解决 any 带来的问题,TypeScript 3.0 引入了unknown 类型。
unknown类型
unknow和any类型的值一样,所有类型的值都可以赋值为unknown:
let notKnownType:unknown = 666
notKnownType = "du" //ok
notKnownType = true //ok
但是unknow和any类型最大的区别在于:any类型的值可以赋值给任何类型;unknow类型的值只能赋值给unknown类型:
let notKnownType:unknown = 666
let b:unknown
b = notKnownType //ok unknown类型的值可以赋值给unknown类型
let num:number = 66
num = notKnownType //Error unknown类型的值不可以赋值给其他类型
这种机制起到了很强的预防性,更安全,这就要求我们必须缩小类型,我们可以使用typeof、类型断言等方式来缩小未知范围:
let notKnownType:unknown = 666
let num:number = 66
//使用typeof先判断unknown类型的值为number类型,然后才可以赋值给number类型
if(typeof(notKnownType) == "number")
num = notKnownType //ok
//使用断言,告知编译器我们知道unknown类型的变量此时存储的类型
num = notKnownType as number //ok
void类型
void表示没有任何类型,和其他类型是平等关系,不能直接赋值:
let a: void;
let b: number = a; // Error
你只能为void类型赋予 null和undefined (在strictNullChecks未指定为true时)。声明一个void类型的变量没有什么大用,我们一般也只有在函数没有返回值时去声明。
值得注意的是,方法没有返回值将得到undefined,但是我们需要定义成void类型,而不是undefined类型。否则将报错:
function fun(): undefined {
console.log("this is TypeScript");
};
fun(); // Error
never类型
never类型表示的是那些永不存在的值的类型,有以下两种两种情况:
- 如果一个函数执行时抛出了异常,那么这个函数永远不存在返回值(因为抛出异常会直接中断程序运行,这使得程序运行不到返回值那一步,即具有不可达的终点,也就永不存在返回了);
- 函数中执行无限循环的代码(死循环),使得程序永远无法运行到函数返回值那一步,永不存在返回。
// 异常
function err(msg: string): never { // OK
throw new Error(msg);
}
// 死循环
function loopForever(): never { // OK
while (true) {};
}
never类型的值只能被never类型的值赋值,其他类型不能赋值给never类型;
当strictNullChecks未指定为true时,never类型同null和undefined类型一样,也是任何类型的子类型,即never类型也可以赋值给任何类型,此时,可以利用 never 类型的特性来实现全面性检查:
type Foo = string | number; //联合类型
function controlFlowAnalysisWithNever(foo: Foo) {
if (typeof foo === "string") {
// 这里 foo 被收窄为 string 类型
} else if (typeof foo === "number") {
// 这里 foo 被收窄为 number 类型
} else {
// foo 在这里是 never,never只能赋值给never
const check: never = foo;
}
}
我们可以确保 controlFlowAnalysisWithNever()方法总是穷尽了 Foo 的所有可能类型。 通过这个示例,我们可以得出一个结论:使用 never 避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。
持续更新中......