TS中的类型
TS中的类型有:number
、string
、boolean
、字面量
、any
、unknown
、void
、never
、object
、array
、tuple
、enum
。其中字面量就是其本身,限制变量的值就是该字面量的值。void表示空(即null或undefined),在函数中就表示该函数没有返回值;never表示永远不返回结果。TypeScript里,undefined
和 null
两者各自有自己的类型分别叫做undefined和null。默认情况下null和undefined是所有类型的子类型,也就是说可以把 null和undefined赋值给number等类型的变量。然而,当指定了 strictNullChecks
标记,null和undefined只能赋值给void和它们各自。某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void
。
字面量
字面量就是其本身,限制变量的值就是该字面量的值。
let a: 'Hello';
a = 'hi'; //报错,a只能是'Hello'
any 和 unknown类型
any
表示的是任意类型,一个变量设置类型为any后相当于对该变量关闭了TS的类型检测。声明变量如果没有指定类型,则ts解析器会自动判断变量的类型为any(隐式any)。 unknown
表示未知类型的值,其实就是有类型安全的any。这两种类型的变量均可随意给其赋值其他类型的数值,如number、string等。
区别:any类型的变量可以赋值给任意变量(除了never类型的变量),unknown类型的变量不可以直接赋值给其它变量。
let a: any;
a = 1;
a = true;
let s: string;
s = a; //隐式any会报错,显式any不会
console.log(typeof s); //boolean
let b: unknown;
b = 1;
b = true;
let s1: string;
s1 = b; //报错,不能将类型unknown分配给类型string
对象类型
语法:{ 属性名:属性值,属性名:属性值 }, 多个属性之间可以用,或;分隔。
let a: { name: string } //a只能有属性name,且属性值类型是string
let b: { name: string, age?: number } //加个?表示可选属性
let c: { name: string, [propName: string]: any } // [propName: string]: any 表示任意类型的属性
c = {name: '七月七',age: 18,sex: '女'} //合法
//函数结构声明 语法:(形参: 类型,形参: 类型...) => 返回值类型
let d: (a: number,b: number) => number //两个形参及返回结果的类型都必须是number
let e: (a: number,b: number) => void //两个形参都必须是number且函数没有返回值
数组 与 元组类型
有两种方式可以定义数组类型:① type[ ]
:type可以是number、string、boolean等; ②数组泛型 Array<>
:尖括号里是元素的类型。元组就是固定长度且有已知元素类型的数组,各元素的类型可以不相同。
let list1: number[] = [1, 2, 3]; //list1内的元素的类型只能是数字类型,即数字数组
let list2: Array<string> = ['小红','小兰','小蓝']; //list2内的元素的类型只能是字符串类型,即字符串数组
//元组语法: [类型(参数1的),类型(参数2的)...]
let tuple: [string, number];
tuple = ['hello', 10];
枚举类型(enum)
使用枚举类型 enum
可以为一组数值赋予友好的名字。默认情况下从0开始为首个元素编号。 另外,也可以手动指定某些元素或全部元素的数值。这样就可以通过枚举类型由枚举的值得到它对应元素的名字。
enum Color {Red, Green=2, Blue} //手动赋值第2个元素的数值,则Red的数值为0,Blue的数值为3
let c: Color = Color.Green;
console.log(c); //2
let colorName: string = Color[3];
console.log(colorName); //'Blue'
console.log(Color); //{ '0': 'Red', '2': 'Green', '3': 'Blue', Red: 0, Green: 2, Blue: 3 }
Never类型
never
类型表示的是那些永不存在的值的类型。 例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never类型,当它们被永不为真的类型保护所约束时。never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外),即使 any也不可以赋值给never。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
联合类型
联合类型是由两种或多种其他类型组成的类型,表示可能是这些类型中的任何一种的值。提供与联合类型匹配的值只需提供与联合的任何成员匹配的类型即可。在TypeScript中只有在对联合体的每个成员都有效的情况下才允许操作,否则会报错。
function printId(id: number | string) {
console.log(id.toUpperCase()); //报错,number类型没有toUpperCase()方法
}
类型别名 与 接口(interface)
在TS中很方便可以通过直接在类型注释中编写对象类型和联合类型来使用它们,但有时希望多次使用同一个类型,于是便用一个名称代替并引用它,这就是类型别名。类型别名可以使得在注释的类型较为复杂时使用方便,不用重复注释该复杂的类型。
type Point = { x: number; y: number };
let obj: Point; //obj则是有两个number类型的属性x和y
接口类型声明:
interface Point { x: number; y: number };
let obj: Point; //obj则是有两个number类型的属性x和y
类型别名和接口的区别:类型别名创建后不能再进行更改,只能通过交叉点(&
)来扩展;接口可进行更改(添加字段属性等)且可扩展,扩展方式与类型别名不同。
//1、扩展方式的区别
//扩展接口
interface Animal { name: string }
interface Bear extends Animal { honey: boolean } //接口Bear就有两个属性name和honey,类型分别是string和boolean
//扩展类型
type Animal = { name: string }
type Bear = Animal & { honey: boolean } //类型Bear就有两个属性name和honey,类型分别是string和boolean
//2、是否可进行更改
interface Win { title: string }
interface Win { ts: number } //接口Win就有两个属性title和ts,类型分别是string和boolean
type Win = { title: string }
type Win = { ts: number } //报错
类型断言
有时我们会比TypeScript更了解某个值的具体信息,这通常会发生在我们清楚地知道一个实体具有比它现有类型更确切的类型。通过 类型断言
这种方式可以告诉编译器,程序员已经进行了必须的检查。类型断言有两种形式:① 尖括号
语法;② as
语法。
//尖括号语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
//as语法
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
这两种形式是等价的。不过,当在TypeScript里使用JSX时,只有 as 语法断言是被允许的。
非空断言运算符
TypeScript 具有一种特殊的语法,用于在不进行任何显式检查的情况下从类型中删除null和undefined,它就是非空断言运算符( !
)。在任何表达式之后写 !
实际上是一个类型断言,表示该值不是null和undefined。
function abc(x?: number | null) {
console.log(x!.toFixed());
}
字面推理
const obj = { counter: 0 };
if (someCondition) {
obj.counter = 1;
}
有时候在遇到上述代码时,ts在编译 obj.counter = 1;
时并不会报错,因为它根据前面 counter: 0
推断出obj.counter的类型是number即可,而不是必须是0。如下述代码:
let req = { url: "https://example.com", method: "GET" };
req.method会被推断为类型string,而不是"GET"。因此,我们可以使用类型断言:
let req = { url: "https://example.com", method: "GET" as "GET"};
这样req.method就始终拥有字面类型"GET"了。