类型
原始数据类型
1. Number
数值
TS
let age: number = 16
let age: number = 16
2. String
字符串
TS
let name: string = 'Tom'
let name: string = 'Tom'
3. Boolean
布尔
TS
let isMale: boolean = true
let isMale: boolean = true
4. Null
TS
let u: undefined = undefined
let u: undefined = undefined
5. Undefined
TS
let u: undefined = undefined
let u: undefined = undefined
引用数据类型
1. Array 数组
1.1 基础表示法
TS
let arr: number[] = [1, 2, 3]
let arr: number[] = [1, 2, 3]
1.2 数组泛型
TS
let arr: Array<number> = [1, 2, 3] // 数组泛型
let arr: Array<number> = [1, 2, 3] // 数组泛型
1.3 类数组
- 数组描述
TS
function sum: void() {
let args = {
[index: number]: number;
length: number;
callee: Function;
} = arguments;
}
function sum: void() {
let args = {
[index: number]: number;
length: number;
callee: Function;
} = arguments;
}
- 接口定义
TS
interface IArguments = {
[index: number]: number;
length: number;
callee: Function;
}
function sum: void() {
let args: IArguments = arguments;
}
interface IArguments = {
[index: number]: number;
length: number;
callee: Function;
}
function sum: void() {
let args: IArguments = arguments;
}
常用的类数组都有内置的接口定义,如
IArguments
,NodeList
,HtmlCollection
等
1.4 数组 any
TS
let list: any[] = [1, 'a', {b: 2}];
let list: any[] = [1, 'a', {b: 2}];
2. Object 对象
- 对象使用
interface
定义类型,一般接口名称前添加I
前缀; - 对象的属性需要与接口定义的属性一一对应,可选、任意属性除外;
interface
的字段结尾使用;
基本用法
TS
function create(o: object | null): void {
}
function create(o: object | null): void {
}
接口定义
TS
interface IPerson {
readonly id: number; // readonly 只读属性,对象被赋值时该字段必须赋值,被赋值后该字段不可修改
name: string;
gender?: string; // ?: 表示可选属性
[propName: string]: any; // 任意属性,确定属性和可选属性的类型必须是它的类型的子集
}
let tom: IPerson = {
id: 1,
name: "Tom",
age: 18
}
interface IPerson {
readonly id: number; // readonly 只读属性,对象被赋值时该字段必须赋值,被赋值后该字段不可修改
name: string;
gender?: string; // ?: 表示可选属性
[propName: string]: any; // 任意属性,确定属性和可选属性的类型必须是它的类型的子集
}
let tom: IPerson = {
id: 1,
name: "Tom",
age: 18
}
3. Function 函数
3.1 函数声明
TS
function sum(x: number, y: number): number {
return x + y;
}
sum(1, 2);
function sum(x: number, y: number): number {
return x + y;
}
sum(1, 2);
3.2 函数表达式
日常写法
TS
let sum = function(x: number, y: number): number {
return x + y;
}
let sum = function(x: number, y: number): number {
return x + y;
}
完整写法
TS
// 注意第一个 => 是表示函数定义,左边是输入类型,右边是输出类型,而不是 ES6 的箭头函数
let sum: (x: number, y: number) => number = function(x: number, y: number): number {
return x + y;
}
// 注意第一个 => 是表示函数定义,左边是输入类型,右边是输出类型,而不是 ES6 的箭头函数
let sum: (x: number, y: number) => number = function(x: number, y: number): number {
return x + y;
}
3.3 可选参数、默认值与剩余参数
TS
// 可选参数
function sum(x: number, y?: number) {
if(y) {
return x + y;
} else {
return x;
}
}
// 默认值
function sum(x: number, y: number = 10) {
return x + y;
}
// 剩余参数
function sum(x: number, ...args: any[]) {
}
// 可选参数
function sum(x: number, y?: number) {
if(y) {
return x + y;
} else {
return x;
}
}
// 默认值
function sum(x: number, y: number = 10) {
return x + y;
}
// 剩余参数
function sum(x: number, ...args: any[]) {
}
3.4 重载
当函数接收不同数量或类型的参数时,作出不同的处理
TS
// 函数定义
function reverse(x: number): number;
function reverse(x: string): string;
// 函数实现
function reverse(x: number | string): number | string | void {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
// 函数定义
function reverse(x: number): number;
function reverse(x: string): string;
// 函数实现
function reverse(x: number | string): number | string | void {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
其它数据类型
1. Void
无类型
一般用于无返回值的函数
TS
function fn(): void {
}
function fn(): void {
}
2. Any
任意类型
- 顶级类型,不会被类型检查
- 变量声明未指定类型,则被识别为任意值类型
- 声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值
TS
let u: any = 'a'
let u: any = 'a'
3. Unknown
顶级类型,用于取代 any
的缺点,注意其与 any
的区别
TS
let some: unknown = 6
let some: unknown = 6
4. Never
5. Emun
枚举类型
- 数字枚举:
TS
enum Gender {
Male,
Female,
}
let tom: Gender = Gender.Male; // 0
enum Gender {
Male,
Female,
}
let tom: Gender = Gender.Male; // 0
- 字符串枚举
TS
enum Gender {
Male = "Male",
Female = "Female",
}
let tom: Gender = Gender.Male; // Male
enum Gender {
Male = "Male",
Female = "Female",
}
let tom: Gender = Gender.Male; // Male
- 异构枚举
TS
enum Enum {
A,
B = "B",
C = 8,
}
Enum.A // 0
Enum.B // "B"
enum Enum {
A,
B = "B",
C = 8,
}
Enum.A // 0
Enum.B // "B"
6. Tuple
元组类型
简单来说元组类型用于定义拥有不同类型元素的数组
TS
let tom: [string, number] = ['Tom', 18];
let tom: [string, number] = ['Tom', 18];
进阶
1. 类型推论
- 如果变量第一次赋值时没有指定类型,会根据第一次赋值的类型进行推论,后续不能赋予其它类型的值
TS
let foo = 'Tom'; // 等价于 let foo: string = 'Tom'
foo = 1; // 报错 Type 'number' is not assignable to type 'string'
let foo = 'Tom'; // 等价于 let foo: string = 'Tom'
foo = 1; // 报错 Type 'number' is not assignable to type 'string'
- 如果变量定义时没有赋值,则会被推断为
any
类型,后续可以被任意赋值
TS
let foo;
foo = 'Tom';
foo = 7;
let foo;
foo = 'Tom';
foo = 7;
2. 联合类型
TS
let foo: string | number;
let foo: string | number;
注意:
- 只能访问联合类型变量的共有属性或方法
TS
function getString(something: string | number): string {
return something.toString(); // 只能使用 string 与 number 的共有方法
}
function getString(something: string | number): string {
return something.toString(); // 只能使用 string 与 number 的共有方法
}
- 联合类型变量被赋值后,会根据类型推论的规则推断出一个类型
TS
let foo: string | number;
foo = 'Tom';
foo.length; // 3
foo.toFixed(2); // 报错
let foo: string | number;
foo = 'Tom';
foo.length; // 3
foo.toFixed(2); // 报错
1. Type
类型别名
类型别名,用于给类型定义新的名字,一般用于联合类型中
TS
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n;
} else {
return n();
}
}
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n;
} else {
return n();
}
}
2. 字符串字面量类型
用来约束取值只能是某几个字符串中的一个
JS
// 使用 type 定义字符串字面量类型 EventNames,它只能取三种字符串中的一种
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
// do something
}
handleEvent(document.querySelector('#hello'), 'scroll'); // 没问题
// 使用 type 定义字符串字面量类型 EventNames,它只能取三种字符串中的一种
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
// do something
}
handleEvent(document.querySelector('#hello'), 'scroll'); // 没问题
3. 类型断言
手动指定一个值的类型
- 值
as
类型(推荐用法)
TS
- <类型> 值
泛型
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
1. 基本用法
TS
function createArray<T>(length: number, value: T): Array<T> {
let arr: T[] = [];
for(let i: number = 0; i < length; i++) {
arr.push(value);
}
return arr;
}
createArray<string>(3, 'a');
function createArray<T>(length: number, value: T): Array<T> {
let arr: T[] = [];
for(let i: number = 0; i < length; i++) {
arr.push(value);
}
return arr;
}
createArray<string>(3, 'a');
2. 多参数
TS
// 输入数组元素位置交换
function swap<T, U>(arr: [T, U]): [U, T] {
return [arr[1], arr[0]];
}
swap([1, 'a']);
// 输入数组元素位置交换
function swap<T, U>(arr: [T, U]): [U, T] {
return [arr[1], arr[0]];
}
swap([1, 'a']);
3. 泛型接口
TS
interface ICreateArray {
<T>(length: number, value: T): Array<T>;
}
let createArray: ICreateArray = function<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
interface ICreateArray {
<T>(length: number, value: T): Array<T>;
}
let createArray: ICreateArray = function<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
将泛型参数提到接口上
TS
interface CreateArrayFunc<T> {
(length: number, value: T): Array<T>;
}
let createArray: CreateArrayFunc<any>;
createArray = function<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
interface CreateArrayFunc<T> {
(length: number, value: T): Array<T>;
}
let createArray: CreateArrayFunc<any>;
createArray = function<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
4. 泛类型
TS
class GenericNumber<T> {
initValue: T;
add: (x: T, y: T) => T;
}
let genericNumber = new GenericNumber<number>();
genericNumber.zeroValue = 0;
genericNumber.add = function(x, y) { return x + y; };
class GenericNumber<T> {
initValue: T;
add: (x: T, y: T) => T;
}
let genericNumber = new GenericNumber<number>();
genericNumber.zeroValue = 0;
genericNumber.add = function(x, y) { return x + y; };
5. 默认参数
TS
function createArray<T = string>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
function createArray<T = string>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
内置对象
ES 内置对象
TS
let e: Error = new Error('Error');
let d: Date = new Date();
let b: Boolean = new Boolean(1);
// 其它
let e: Error = new Error('Error');
let d: Date = new Date();
let b: Boolean = new Boolean(1);
// 其它
DOM / BOM 内置对象
Document
、HTMLElement
、Event
、NodeList
等。
TS
let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) {
// Do something
});
let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) {
// Do something
});
声明合并
定义多个相同名字的函数、接口或类,会被合并为一个类型
1. 函数合并
即函数重载
2. 接口合并
- 不同属性合并
- 相同属性且类型一致会覆盖,类型不一致会报错
- 相同名称的方法与函数合并一致,都会保留,即函数重载
TS
interface IPerson {
name: string;
run(speed: number): number;
}
interface IPerson {
age: number;
run(speed: number, time: number): number;
}
interface IPerson {
name: string;
run(speed: number): number;
}
interface IPerson {
age: number;
run(speed: number, time: number): number;
}
等同于:
TS
interface IPerson {
name: string;
age: number;
run(speed: number): number;
run(speed: number, time: number): number;
}
interface IPerson {
name: string;
age: number;
run(speed: number): number;
run(speed: number, time: number): number;
}
3. 类合并
与接口合并一致