基础
数据类型
// 布尔值
const isDone: boolean = false;
// 数值
const num: number = 1;
// 字符串
const myName: string = "Tom";
// 函数返回空 / 没有任何类型
const alertName = (): void => {
console.log("My name is Tom");
};
// 变量没有值的初始状态; 任何类型的子类型
const u: undefined = undefined;
// undefined 是任何类型的子类型, 可赋值给 number
let num: number = undefined;
// 表示什么都没有; 任何类型的子类型
const n: null = null;
// 可赋予任何类型, 可使用任何类型的属性和方法
let anyThing: any = "Tom";
// 不知道类型的变量, 需类型断言确定类型
const unknown: unknown = 1;
// 永远不存在值的类型, 抛出异常时返回 never
const never: never = 1;
// void 表示没有任何类型
function warnUser(): void {
console.log("This is my warning message");
}
接口
定义接口
interface Person {
// 只读属性, 不能被修改
readonly id: number;
// 必须属性, 不能省略
name: string;
// 可选属性, 可以省略
age?: number;
// 任意属性, 任意类型的属性
[propName: string]: string | number;
}
接口继承接口
interface Alarm { console.log(): void; }
interface LightableAlarm extends Alarm {
lightOn(): void;
lightOff(): void;
}
函数类型
定义函数类型
function (x: number, y: number): number { return x + y; };
const sum = (x: number, y: number): number => { return x + y; };
// 可选参数, 位于必选参数后
const buildName = (firstName: string, lastName?: string) => {};
// 默认参数值
const buildName = (firstName: string, lastName: string = "kong") => {};
// 剩余参数, 任意数量参数, 位于最后
const push = (array: any[], ...items: any[]) => {};
函数重载
- 同一个函数接受不同数量或类型的参数;
// 普通函数
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("");
}
}
// 箭头函数
interface FN {
(x: number): number;
(x: number, y: number): number;
}
const reverse1: FN = (x: number, y?: number): number => {
if (y) {
return x + y;
} else {
return x;
}
};
const reverse2 = ((x: number, y?: number): number => {
if (y) {
return x + y;
} else {
return x;
}
}) as FN;
联合类型和交叉类型
联合类型
- 表示几个类型中的一个;
- 只能访问联合类型共有的方法和属性;
let myFavoriteNumber: string | number;
myFavoriteNumber = "seven";
myFavoriteNumber = 7;
交叉类型
- 将多个类型合并在一起;
- 具有多个类型的属性和方法;
interface ErrorHandling {
success: boolean;
error?: { message: string };
}
interface ArtworksData {
artworks: { title: string }[];
}
type ArtworksResponse = ArtworksData & ErrorHandling;
字面量类型
- 约束取值只能为规定值中的一个;
type EventNames = "click" | "scroll" | "mousemove";
const handleEvent = (ele: Element, event: EventNames) => {};
handleEvent(document.getElementById("hello"), "scroll");
handleEvent(document.getElementById("world"), "dblclick"); // 报错, event 不能为 'dblclick'
数组类型
// 类型 + 方括号
let fibonacci: number[] = [1, 1, 2, 3, 5];
let fibonacci: object[] = [1, 1, 2, 3, 5];
// 泛型
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
// 接口
interface NumberArray {
[index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
元组
语法格式
- 各项类型不同且固定;
- 初始化元组需要赋值所有项;
const tom: [string, number] = ["Tom", 25];
越界元素
- 类型限制为元组中各类型的联合类型;
枚举
语法格式
- enum 用于取值限制在一定范围内的场景;
- enum 成员赋值为从 0 递增的数字, 枚举值和枚举名相互映射;
enum Directions {
Up,
Down,
Left,
Right,
}
Directions[0] = "Up";
Directions["Up"] = 0;
手动赋值
- 未手动赋值的根据上一个枚举项递增;
- 手动赋值可能出现重复值, ts 不报错, 应避免;
enum Directions {
Up = 3,
Down = 2,
Left,
Right,
}
替代
- enum 无法翻译为原生 js;
- 推荐使用
as const替代 enum;
const Directions = { Up: 3, Down: 2, Left: 1, Right: 0 } as const;
类型断言
语法格式
- 具有
<>和as两种声明形式; - 推荐使用
as;
const tom = getCacheData("tom") as Cat;
const tom = <Cat>getCacheData("tom");
双重断言
- 可将任意类型断言为另一任意类型;
- 不建议使用;
A as any as B;
类
基本概念
访问修饰符
public: 公有, 任何地方均可访问;private: 私有, 仅能从声明类内部访问;protected: 保护, 仅能从声明类及其子类内部访问;
class Animal {
private name;
public constructor(name) {
this.name = name;
}
}
let a: Animal = new Animal("Jack");
readonly
- 只读修饰符;
- 与其他访问修饰符共存时, 放在其后;
class Animal {
public constructor(public readonly name) {}
}
abstract
- 定义抽象类及其抽象方法;
- 抽象类和方法不能被实例化;
abstract class Animal {
public name;
public constructor(name) {
this.name = name;
}
public abstract sayHi();
}
类和接口
类实现接口
interface Alarm { console.log(): void; }
interface Light { lightOn(): void; lightOff(): void; }
class Car implements Alarm, Light {
console.log() { console.log("Car alert"); }
lightOn() { console.log("Car light on"); }
lightOff() { console.log("Car light off"); }
}
类继承接口
- 声明类的同时声明了一个同名类型;
- 创建的同名类型中只包含类的实例属性和方法;
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = { x: 1, y: 2, z: 3 };
泛型
基本概念
泛型
- 运行时确定类型;
语法格式
// 普通函数
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
// 箭头函数
const createArray = <T>(length: number, value: T): Array<T> => {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
};
// 确定类型
createArray<string>(3, "x"); // ['x', 'x', 'x']
多个类型参数
const swap = <T, U>(tuple: [T, U]): [U, T] => {
return [tuple[1], tuple[0]];
};
泛型参数的默认类型
- 未指定类型且 ts 无法推断时, 使用默认类型;
const createArray = <T = string>(length: number, value: T): Array<T> => {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
};
泛型约束
- 函数内部使用泛型时无法使用类型的属性和方法;
- 使用泛型约束指定其包含的属性和方法;
interface Lengthwise {
length: number;
}
const loggingIdentity = <T extends Lengthwise>(arg: T): T => {
console.log(arg.length);
return arg;
};
泛型接口
- 通过定义泛型接口定义函数形状;
interface CreateArrayFunc {
<T>(length: number, value: T): Array<T>;
}
const createArray: CreateArrayFunc = <T>(
length: number,
value: T,
): Array<T> => {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
};
泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
return x + y;
};
高级类型
类型推断
基础
- 未指明类型时根据规则判断变量类型;
基本类型推断
- 根据表达式右侧的值推断左侧变量类型;
- 赋值操作: 初始化变量, 默认参数值;
- 函数 return 返回类型;
最佳通用类型推断
- 常用于数组类型推断;
- 根据最佳通用类型算法选择与所有数组子项类型兼容的数组类型;
上下文类型推断
- 常用于事件处理中对 e 的判断;
- 根据使用变量的位置判断其类型;
类型守卫
使用场景
interface Bird {
fly();
layEggs();
}
interface Fish {
swim();
layEggs();
}
function getSmallPet(): Fish | Bird {}
let pet = getSmallPet();
pet.layEggs(); // okay
// 无法判断 pet 是 Bird 或者 Fish, 故不能使用 swim() 方法
pet.swim(); // errors
类型判定
parameter is type;
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
if (isFish(pet)) {
pet.swim();
} else {
pet.fly();
}
使用 in 操作符
in操作符判断类型是否具有某属性;
function move(pet: Fish | Bird) {
if ("swim" in pet) {
return pet.swim();
}
return pet.fly();
}
typeof
- ts 自动把
typeof作为类型守卫;
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
instanceof
- ts 自动把
instanceof作为类型守卫;
// 类型为SpaceRepeatingPadder | StringPadder
let padder: Padder = getRandomPadder();
if (padder instanceof SpaceRepeatingPadder) {
padder; // 类型细化为'SpaceRepeatingPadder'
}
if (padder instanceof StringPadder) {
padder; // 类型细化为'StringPadder'
}
索引类型
keyof
keyof T为 T 上所有公共属性的联合;
interface Car {
manufacturer: string;
model: string;
year: number;
}
// 'manufacturer' | 'model' | 'year'
let carProps: keyof Car;
索引访问操作符
K extends keyof T;
function getProperty<T, K extends keyof T>(o: T, propertyName: K): T[K] {
return o[propertyName]; // o[propertyName] is of type T[K]
}
工具类型
// 所有属性变为可选; { [P in keyof T]?: T[P]; }
type PersonPartial = Partial<Person>;
// 所有属性变为必选; { [P in keyof T]-?: T[P]; }
type RequiredContact = Required<Contact>;
// 所有属性变为只读; { readonly [P in keyof T]: T[P]; }
type ReadonlyPerson = Readonly<Person>;
// 选取指定属性; { [P in K]: T[P]; }
type ContactPick = Pick<Contact, "name" | "phone">;
// 移除指定属性; Pick<T, Exclude<keyof T, K>>
type OmitEmailContact = Omit<Contact, "email">;
type Fruit = "apple" | "banana" | "orange";
// 生成属性为 K, 值为 T 的类型
type Inventory = Record<Fruit, number>;
type Platform = "Windows" | "MacOS" | "Linux" | "iOS" | "Android";
// 排除联合类型中指定类型
type DesktopPlatform = Exclude<Platform, "iOS" | "Android">;
// 条件类型: 若 T 能赋值 U 则为 X, 反之为 Y
declare function f<T extends boolean>(x: T): T extends true ? string : number;
let x = f(Math.random() < 0.5);
操作符
// 非空断言, 表示 map 一定有值
map!;
// 可选链, map 非空时执行 getLayer(), 为空时返回 undefined
map?.getLayer();
// 空值合并, 左侧为 null 或 undefined 时返回右侧, 反之返回左侧
const foo = null ?? "default string";
声明文件
基本概念
声明文件
- 用于声明第三方库类型, 变量, 方法等;
后缀名
.d.ts为后缀;
自定义类型
export type CaseListData = {
key: string;
title: string;
data: string[];
};