注: symbol 为ES6中新增类型
类型
- string /boolean /number
// 字符串:支持es6 拼接
let sport:string = '足球'
let hobby:string;
hobby = `我爱${sport}` // 支持es6 拼接 ``
console.log( hobby)
// 布尔值
let choice:boolean = false
// 数值: 和JavaScript一样,TypeScript里的所有数字都是浮点数。支持二进制、八进制、十进制、十六进制、整数和小数(整数可以算进十进制)、NaN(非数字)、Infinity(无穷大)
let binNum:number = 0b110 // 二进制
let octNum:number = 0o6 // 八进制
let num:number = 6// 十进制
let hexNum:number = 0x6 // 十六进制
let maxNum:number = Infinity // 无穷大
let isNaNum:number = NaN // 非数值
注意:
(1)这里的string是小写的,和String是有区别的
(2)使用构造函数(Boolean
、String
、Number
)创造的对象并不是布尔值,而是返回一个对象。直接调用Boolean()
则返回一个布尔值,常用于将一个值强制转换为boolean类型,在此我以构造函数 Boolean
为例:
let isBoolean:boolean = new Boolean(1) // 报错'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.
let isBoolean:boolean = Boolean(1) // true
- array 数组
- 特点
元素类型限制,长度不限制
方式1:类型[]
let array: number[] = [1, 2, 3, 4];
数组的一些方法的参数也会根据数组在定义时约定的类型进行限制:
array.push('2');
// 报错:Argument of type 'string' is not assignable to parameter of type 'number'
方式2:Array<类型>
(Array Generic) 数组泛型表示数组
let array: Array<number> = [1, 2, 3, 4];
自己写数组泛型
方式3:接口(不推荐)
数组的索引就是 number 类型的 0,1,2,3..., JS 中数组是一类特殊的对象,特殊在数组的键(索引)是数值类型
MyArray 接口模拟原生的数组接口,并使用 [n: number]来作为索引签名类型。
interface MyArray<T> {
[index:number]: T
}
const testArray: MyArray<string> = ["1", "2", '3']
const testArray2: MyArray<number> = [1, 2, 3]
类数组:
类数组不是数组,使用数组的类型会报错
function add() {
let args: number[] = arguments;
}
// 报错:Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 26 more.
arguments 为类数组,应该使用下面这种方式定义类型
function sum() {
let args: {
[index: number]: number;
length: number;
callee: Function;
} = arguments;
}
其实常用的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection 等
function add() {
let args: IArguments = arguments;
}
- tuple 元组
- 语法
let 元组名:[类型1,类型2,类型3] = [值1, 值2,值3]
- 使用
let tup1:[number, string, boolean] = [1, '3', true]
当直接对元组中的变量进行初始化的时候,变量的数量及变量对应的类型必须与类型指定一致 ,否则报错
let tup1:[number, string, boolean] = [1, '3', true]
let tup2:[number, string, boolean] = [1, '3'] // Property '2' is missing in type '[number, string]' but required in type '[number, string, boolean]'.
let tup3:[number, string] = [1, 3] // Type 'number' is not assignable to type 'string'.
需要注意元祖的越界问题,虽然可以越界添加元素,但是不能越界访问,强烈不建议这么使用,而且越界的元素的类型会被限制为元组中每个类型的联合类型:
let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true);
// Argument of type 'boolean' is not assignable to parameter of type 'string | number'
let tup4:[string, number] = ['1', 3]
tup3[0] = 'Tom'
tup3.push('apple')
console.log(tup3) // ["Tom", 3, "apple"]
console.log(tup3[2]) // Tuple type '[string, number]' of length '2' has no element at index '2'
- 特点
长度限制,每个元素的类型限制,但不同元素类型可不同
其实,可以和数组进行对比理解:
数组是合并了相同类型的对象,而元组(Tuple)则是合并了不同类型的对象,且类型和数量已定
- enum 枚举
- 语法
enum 枚举名{
枚举项1 = 值1,
枚举项2 = 值2 ...
}
注:枚举项名称一般由英文和数字组成,值一般用数字,默认为0,1,2...
-
使用
默认情况下是从0开始为元素编号
enum gender1 {
male,
female,
unkown
}
console.log(gender1.male) // 0
也可以手动的部分指定成员的数值或全部,后面的成员一次加1
enum gender2 {
male,
female = 2.5,
unkown
}
console.log(gender2.male) // 0
console.log(gender2.unkown) // 3.5
- 特点
长度限制,每个元素的类型限制,但不同元素类型可不同
可以理解为:定了元素类型和数量的数组,但多个元素类型可不同
-
any 任意类型
一般来说,如果一个变量赋值为某个类型,在赋值过程中是不允许改变类型的,但是any 类型除外,允许被赋值为任意类型。any类型 一般用在不清楚变量的类型的情况。 在这种情况下,不想让类型检查器对这些值进行检查。 就可以使用
any
类型来标记这些变量
- 语法
let 变量名: any;
用来表示允许赋值为任意类型。
- 使用
let anyThing1:any
anyThing1 = 'dd'
anyThing1 = 123
let anyThing2: any[] = [1, true]
anyThing2.push('222')
anyThing2[1] = undefined
console.log(anyThing2) // [1, undefined, "222"]
如果变量在声明的时候未指定其类型,那么它会被识别为任意值类型:
let something; // 等同于var something:any;
something = 'seven';
something = 7;
console.log(something); // 7
- void
没有任何类型,从一定角度可以认为void
类型与any
类型相反。但是在写代码的过程中一般不会单独声明一个void
类型的变量,因为其只能赋值undefined
和null
,意义不大
let unusable: void = undefined;
void一般用在当一个函数没有返回值时,设置返回值类型为 void
:
function sayHi(): void {
console.log("Hi,everyone");
}
- null和undefined
undefined
和null
都有自己的类型,分别为undefined
和null
。但是这并没有多大意义。
let undefType:undefined = undefined
let nullType:null = null
默认情况下null
和undefined
是所有类型的子类型。 就是说你可以把 null
和undefined
赋值给其他类型的变量,但是如果设置了--strictNullChecks
严格的空校验 ,null
和undefined
只能赋值给void
和自身。 在写代码的过程中建议开启空校验。 如果某个变量的类型可能为 number
或null
或undefined
,建议使用联合类型number | null | undefined
- never类型
表示永不存在的值的类型,一般用作抛出异常或无限循环的函数返回类型。
function test():never{
while (true){
...
}
}
function test2():never{
throw new Error('Error');
}
never
类型是ts中的底部类型,是所有类型的子类型,因此可以赋值给任何类型变量
let cat:string = test()
- 联合类型
在实际写代码的过程中,有时候定义的变量的类型可能是多种的,因此联合类型便派上用场了。
- 语法
let 变量名:类型1|类型2... = 值
- 使用
let info:string|null|number;
info = 22
info = '你好吗'
info = null
let infoArr:(string|number)[];
infoArr = [12, 'sad', 222]
当不确定变量是哪个类型的时候,只能访问此联合类型的所有类型里共有的属性或方法
let temp:(string|number|boolean);
console.log(temp.length) // Property 'length' does not exist on type 'number'.
9.交叉类型
类似于接口继承,用于组合多个类型为一个类型(常用于对象类型)
interface Person { name: string }
interface People { sex: string }
type PersonMan = Person & People
相当于:
type PersonMan = {name: string, sex: string }
当交叉的类型里有相同属性时
interface Person {
name: string;
title: string | number;
}
interface People {
name: number;
sex: string;
title: string;
}
type PersonMan = Person & People;
let dan: PersonMan = {
name: 'ww', // name 报错:Type 'string' is not assignable to type 'never'.
sex: 'girl',
title: 'title',
};
name 类型推导结果是 never,因为不存在一个值既是 string 又是 number 的。
title 类型推导结果是 string
总结:
交叉类型算的是 2 个类型的 并集。就是双方都有的东西才能合并到一起,不一样的将会被排除
如果排除到最后都没有相同的东西,那么就会变 never 类型(即该类型不存在)
内置类型(string,number,boolean,unio 联合类型)之间可以使用 &
-
映射类型
参考
映射类型是指基于现有类型产生新的类型
通过遍历语法拷贝原有类型 在拷贝类型的基础上进行修改从而产生新的类型
语法:
{[P in K]: T}
Partial 将每个属性转换为可选属性
type Partial<T> = {
[P in keyof T]?: T[P];
}
type PersonPartial = Partial<Person>;
Readonly 将每个属性转换为只读属性
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
type ReadonlyPerson = Readonly<Person>;
Pick 选取一组属性指定新类型
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
}
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
Exclude 去除交集,返回剩余的部分
type Exclude<T, U> = T extends U ? never : T
interface Props {
a?: number;
b?: string;
}
const obj: Props = { a: 5 };
const obj2: Required<Props> = { a: 5 };
Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'
Nullable 转换为旧类型和null的联合类型
type Nullable<T> = {
[P in keyof T]: T[P] | null
}
type NullablePerson = Nullable<Person>;
Omit 适用于键值对对象的Exclude,去除类型中包含的键值对
type Omit = Pick<T, Exclude<keyof T, K>>
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Omit<Todo, "description">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
Required 将每个属性转换为必选属性
type Required<T> = {
[P in keyof T]-?: T[P]
}
interface Props {
a?: number;
b?: string;
}
const obj: Props = { a: 5 };
const obj2: Required<Props> = { a: 5 };
- 接口
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
接口一般首字母大写。
注意:定义的变量比接口多或者少了一些属性是不允许的:
可选属性
interface Person {
name: string;
age?: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
建议:
书写的时候可选属性建议放在最后
任意属性
interface Person {
name: string;
age?: number;
[key: string]: any;
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
注意:
一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
interface Person {
name: string;
age?: number;
[key: string]: string;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
// 报错:Property 'age' of type 'number' is not assignable to 'string' index type 'string'.
一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,则可以在任意属性中使用联合类型:
interface Person {
name: string;
age?: number;
[key: string]: string | number;
}
建议:
实际开发中不要使用过多的任意类型,使用到什么属性就把对应的类型添加到接口里即可。
只读属性
如果只希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性:
// interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
id: 89757,
name: 'Tom',
gender: 'male'
};
tom.id = 9527;
// 报错:Cannot assign to 'id' because it is a read-only property.
-
字符串字面量
字符串字面量类型用来约束取值只能是某几个字符串中的一个。
type EventNames = 'click' | 'scroll' | 'mousemove';
网友评论