干货无需过多废话,直接上内核
- 泛型(Generics) : 泛型允许你为类、接口和方法定义可重用的类型参数化组件。
function identity<T>(arg: T): T {
return arg;
}
- 装饰器(Decorators) : 装饰器是一种特殊类型的声明,它可以被附加到类声明、方法、访问器或属性上,用于修改它们的行为。
function logClass(target: Function) {
console.log('Class decorated:', target);
}
@logClass
class MyClass {}
- 混入(Mixins) : 混入是一种重用类功能的方式,可以将多个类的功能组合到一个类中。
class Mixin {
mixinMethod() {
console.log('Mixin method');
}
}
class MyClass extends Mixin {
myClassMethod() {
console.log('My class method');
}
}
const myObj = new MyClass();
myObj.mixinMethod();
- 类型守卫(Type Guards) : 类型守卫用于在运行时检查类型,以便在TypeScript中执行类型缩小操作。
function isString(value: any): value is string {
return typeof value === 'string';
}
function processValue(value: string | number) {
if (isString(value)) {
console.log(value.toUpperCase());
}
}
- 映射类型(Mapped Types) : 映射类型允许你从现有的类型创建新的类型,通过对每个属性进行转换。
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
interface Person {
name: string;
age: number;
}
type ReadonlyPerson = Readonly<Person>;
type PartialPerson = Partial<Person>;
- 条件类型(Conditional Types) : 条件类型允许你根据条件表达式从两种或多种类型中选择一种类型。
type IsString<T> = T extends string? true : false;
type Result = IsString<string>;
- 联合类型(Union Types) : 联合类型允许一个变量是多种类型之一。
function logId(id: number | string) {
console.log(`ID: ${id}`);
}
- 交叉类型(Intersection Types) : 交叉类型将多个类型组合成一个类型,适用于将多个对象的特性合并。
interface Person {
name: string;
age: number;
}
interface Worker {
jobTitle: string;
}
type Employee = Person & Worker;
const employee: Employee = {
name: "张三",
age: 30,
jobTitle: "工程师",
};
- 索引类型(Index Types) :索引类型用于获取对象类型的特定属性类型。
type Person = {
name: string;
age: number;
};
type PersonName = Person['name']; // string
- 类型推断(Type Inference) : TypeScript可以根据上下文推断出类型。
const num = 10; // TypeScript 推断 num 为 number
- 模板字面量类型(Template Literal Types) : 使用模板字面量类型可以创建新的字符串类型。
type EventName = "click" | "mouseover";
type EventHandler = `on${Capitalize<EventName>}`;
const handler: EventHandler = "onClick"; // 正确
// const invalidHandler: EventHandler = "onHover"; // 错误
- 接口(Interfaces) :接口用于定义对象的结构,可以被类实现,也可以用于类型检查。
interface Animal {
name: string;
makeSound(): void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound() {
console.log("汪汪!");
}
}
- 类(Classes) :TypeScript 支持面向对象编程,可以使用类来创建对象。
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet() {
console.log(`你好,我是 ${this.name},今年 ${this.age} 岁。`);
}
}
- 命名空间(Namespaces) :命名空间用于将相关的代码组织在一起,避免污染全局范围。
namespace Geometry {
export class Circle {
constructor(public radius: number) {}
area() {
return Math.PI * this.radius ** 2;
}
}
}
const circle = new Geometry.Circle(5);
console.log(circle.area());
- 模块(Modules) :模块是将代码组织成独立文件的方式,可以使用
export和import关键字进行模块间的导入导出。
// shapes.ts
export class Rectangle {
constructor(public width: number, public height: number) {}
}
// app.ts
import { Rectangle } from './shapes';
const rect = new Rectangle(10, 20);
- 类型声明文件(.d.ts) :类型声明文件用于为 JavaScript 库提供类型信息,以便 TypeScript 用户能够获得类型检查和自动补全的支持。
// jquery.d.ts
declare module "jquery" {
function $(selector: string): any;
export = $;
}
- 类型泛化(Type Assertion) :类型断言允许开发者手动指定某个值的类型,通常用于从一个类型转变成另一个类型。
const someValue: unknown = "这是一个字符串";
// 使用类型断言
const strLength: number = (someValue as string).length;
- 三斜线指令(Triple-Slash) 指令 :TypeScript 中的一种特殊注释格式,通常用于在代码中引入类型声明或模块。它们以三个斜杠开始,后面跟着特定的指令。
- 1.
/// <reference path="..." />
这个指令用于引入其他 TypeScript 文件的类型定义。在一个文件中,你可以使用这个指令来引用其他文件,使得当前文件能够使用那些文件中定义的类型。
/// <reference path="moduleA.ts" />
/// <reference path="moduleB.ts" />
- 2.
/// <reference lib="..." />
这个指令用于引入 TypeScript 的内置库,比如 DOM、ES5、ES6 等。这在需要使用特定库的类型时非常有用。
/// <reference lib="es2015" />
- 3.
/// <reference types="..." />
这个指令用于引入类型定义文件。通常在使用第三方库时,类型定义文件(例如从 DefinitelyTyped 提供的)可以通过这个指令来使用。
/// <reference types="node" />
- 函数重载(Function Overloading) :函数重载(Function Overloading)是指可以使用相同的函数名来定义多个不同的函数签名。这使得一个函数可以根据不同的参数类型或数量来执行不同的操作。函数重载在处理多种类型的输入时非常有用。 函数重载的要点(相同函数名(重载的函数具有相同的名称,但具有不同的参数类型或参数数量)、不同的签名(每个重载定义都称为“签名”,它描述了函数接受的参数类型和数量)、具体的实现(重载函数的实际实现(即函数体)通常使用联合类型来处理所有可能的输入类型,在实现逻辑中需要根据参数类型进行相应的处理))
// 函数重载签名
function handleInput(input: string): string; // 重载签名 1
function handleInput(input: number): number; // 重载签名 2
// 函数实现
function handleInput(input: any): any {
if (typeof input === "string") {
return `输入的是字符串: ${input}`;
} else if (typeof input === "number") {
return input * 2;
}
}
// 调用重载函数
const result1 = handleInput("Hello"); // 结果: 输入的是字符串: Hello
const result2 = handleInput(10); // 结果: 20
// **重载签名**:前两行定义了重载签名。每个签名都指定了不同的参数类型(`string` 和 `number`)
// 实际的函数实现必须涵盖所有可能的输入类型。在此示例中,使用 `typeof` 操作符来判定输入的类型,并根据类型执行不同的操作
- 协变(Covariance)和逆变(Contravariance) :协变(Covariance)和逆变(Contravariance)是指类型之间的关系,主要用于描述函数参数和返回值在类型系统中的兼容性。这些概念通常涉及到函数签名和泛型。
-
- 协变(Covariance)
协变是指如果类型 A 是类型 B 的子类型,则 A 可以替代 B。在实际应用中,协变通常体现在函数的返回值类型上。例如,如果一个函数返回类型是 B,而我们有一个返回类型为 A 的子类函数,那么这个子类函数可以用作父类函数的返回类型。
class Animal {
name: string;
}
class Dog extends Animal {
bark() {
console.log("汪汪!");
}
}
function getAnimal(): Animal {
return new Dog(); // 协变,返回类型 Dog 是 Animal 的子类型
}
const dog: Animal = getAnimal(); // 合法
-
- 逆变(Contravariance)
逆变是指如果类型 A 是类型 B 的子类型,则 B 可以替代 A。逆变通常与函数参数类型有关。如果一个函数接受参数类型 A,那么一个接受参数类型 B(其中 B 是 A 的父类)的函数可以用作 A 类型的参数。
class Animal {
name: string;
}
class Dog extends Animal {
bark() {
console.log("汪汪!");
}
}
// 这里的参数是 Animal,意味着可以接受任何 Animal 类型的子类
function handleAnimal(animal: Animal) {
console.log(animal.name);
}
// 参数是 Dog,Dog 是 Animal 的子类
function handleDog(dog: Dog) {
console.log(dog.name);
}
// 逆变,接受 Animal 类型的函数可以接受 Dog 类型的函数
let handler: (animal: Animal) => void = handleDog; // 合法
handler(new Dog()); // 合法
// 但反过来就不行,因为 handleAnimal 期望 Animal,这里类型不匹配
// handleDog = handleAnimal; // 错误
小结
- 协变指的是返回值类型的兼容性,允许使用子类返回父类期望的类型。
- 逆变指的是参数类型的兼容性,允许使用父类作为子类期望的参数类型。
- 高级类型工具(Advanced Type Tools) :TypeScript 的高级类型工具为开发者提供了强大的类型系统,能够更加灵活地处理复杂的数据结构和类型。
- 1. Partial
Partial<T> 将类型 T 的所有属性变为可选属性。这在需要部分更新对象时非常有用。
interface User {
id: number;
name: string;
email: string;
}
type PartialUser = Partial<User>;
const userUpdate: PartialUser = {
name: "张三"
}; // 合法
- 2. Required
Required<T> 将类型 T 的所有属性变为必需属性。用来确保对象中不能有可选属性。
interface User {
id: number;
name?: string;
}
type RequiredUser = Required<User>;
const user: RequiredUser = {
id: 1,
name: "李四" // name 现在是必需的
}; // 合法
- 3. Readonly
Readonly<T> 将类型 T 的所有属性变为只读属性。对象的属性不能被修改。
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
const user: ReadonlyUser = {
id: 1,
name: "王五"
};
// user.id = 2; // 错误,不能修改只读属性
- 4. Record<K, T>
Record<K, T> 用于构造一个对象类型,其属性名是类型 K,属性值是类型 T。常用于映射。
type UserRoles = 'admin' | 'user' | 'guest';
type RolePermissions = Record<UserRoles, string[]>;
const permissions: RolePermissions = {
admin: ['create', 'read', 'update', 'delete'],
user: ['read'],
guest: ['read']
};
- 5. Omit<T, K>
Omit<T, K> 用于从类型 T 中剔除属性 K。
interface User {
id: number;
name: string;
email: string;
}
type UserWithoutEmail = Omit<User, 'email'>;
const user: UserWithoutEmail = {
id: 1,
name: "李四"
}; // 合法
- 6. Pick<T, K>
Pick<T, K> 用于从类型 T 中选择一些属性 K,并构造一个新的类型。
interface User {
id: number;
name: string;
email: string;
}
type PickedUser = Pick<User, 'name' | 'email'>;
const user: PickedUser = {
name: "赵六",
email: "zhaoliu@example.com"
}; // 合法
- 7. Exclude<T, U>
Exclude<T, U> 用于从类型 T 中排除类型 U。
type Original = 'a' | 'b' | 'c' | 'd';
type Excluded = Exclude<Original, 'a' | 'b'>; // 'c' | 'd'
- 8. Extract<T, U>
Extract<T, U> 用于提取类型 T 中可以赋值给类型 U 的部分。
type Original = 'a' | 'b' | 'c' | 'd';
type Extracted = Extract<Original, 'a' | 'b'>; // 'a' | 'b'
- 9. NonNullable
NonNullable<T> 用于从类型 T 中排除 null 和 undefined。
type MaybeString = string | null | undefined;
type NonNullableString = NonNullable<MaybeString>; // string
- 10. ReturnType
ReturnType<T> 用于获取函数 T 的返回类型。
function getAge(): number {
return 30;
}
type Age = ReturnType<typeof getAge>; // Age 是 number
- 11. InstanceType
InstanceType<T> 用于获取构造函数类型 T 的实例类型。
class Person {
constructor(public name: string) {}
}
type PersonInstance = InstanceType<typeof Person>;
const person: PersonInstance = new Person("李四"); // 合法
- 12. ThisType
ThisType<T> 是一个特殊的工具类型,用于在函数指针类型中指定 this 的类型。
interface User {
name: string;
greet(this: User): string;
}
const user: User = {
name: "王五",
greet() {
return `你好,我是 ${this.name}`;
}
};
console.log(user.greet()); // 输出: 你好,我是 王五
- 13. keyof
keyof 是一个索引类型查询操作符,它返回一个类型的所有键组成的联合类型。这在需要灵活访问对象属性时非常有用。
interface User {
id: number;
name: string;
email: string;
}
// 使用 keyof 获取 User 的键
type UserKeys = keyof User; // "id" | "name" | "email"
// 示例函数,接受 UserKeys 类型的参数
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user: User = { id: 1, name: "王五", email: "wangwu@example.com" };
const userName = getValue(user, "name"); // "王五"
- 14. infer
infer 是用于条件类型中的一种特性,可以在条件表达式中推断类型。当你想要从一个类型中提取出某一部分的类型时,使用 infer 可以非常方便。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function exampleFunction() {
return 42;
}
type ResultType = ReturnType<typeof exampleFunction>; // ResultType 是 number
- 15.
Promise<T>
Promise 的泛型使得你可以明确指定 Promise 返回值的类型。这在处理不同类型的异步操作时非常有用。
interface User {
id: number;
name: string;
}
function fetchUser(id: number): Promise<User> {
return new Promise<User>((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
const user: User = { id, name: "李四" };
resolve(user); // 成功解析 User 类型
}, 1000);
});
}
// 使用 fetchUser 函数
fetchUser(1)
.then((user) => {
console.log(`用户 ID: ${user.id}, 名称: ${user.name}`);
})
.catch((error) => {
console.error(`获取用户时出错: ${error}`);
});
联合类型(Union Type)和交叉类型(Intersection Type)的区别
联合类型(Union Type) :
- 联合类型允许一个变量可以是多种类型中的一种。例如,可以将一个变量定义为
string | number,这意味着该变量可以是字符串类型或数字类型。
function log(value: string | number) {
console.log(value);
}
log("Hello"); // 有效
log(100); // 也有效
交叉类型(Intersection Type) :
- 交叉类型用于将多个类型合并为一个类型。它代表一个既符合所有类型的实例。例如,可以将一个变量定义为
A & B,这意味着该变量既是类型 A 的实例,也是类型 B 的实例。
interface A {
name: string;
}
interface B {
age: number;
}
const person: A & B = {
name: "Alice",
age: 30,
};
总结:
- 联合类型用于表示一个值可以是几种类型之一。
- 交叉类型用于表示一个值必须同时符合多个类型的要求。
以上便是ts好用并且可能不常见的用法了。。。