当前位置: 首页 > article >正文

TypeScript实用笔记(三):泛型<T>的使用 <T>的12种工具类型的使用

文章目录

  • 一、理解
  • 二、使用
    • 1. 泛型函数
      • 1.1 单一类型参数的泛型函数
      • 1.2 泛型数组
      • 1.3 多个类型参数的泛型函数
      • 1.4 泛型约束
      • 1.5 默认类型参数
      • 1.6 使用泛型约束和函数重载
    • 2. 泛型接口
      • 2.1 单类型参数的泛型接口
      • 2.2 多类型参数的泛型接
      • 2.3 泛型约束
      • 2.4 默认类型参数
      • 2.5 复杂类型
    • 3. 泛型类
      • 3.1 单类型参数的泛型类
      • 3.2 多个类型参数的泛型类
      • 3.3 泛型约束
      • 3.4 默认类型参数
      • 3.5 复杂类型
  • 三、工具类型
    • 1. Partial\<T>: 将对象类型的所有属性变为可选
    • 2. Required\<T>: 将对象类型的所有属性变为必选
    • 3. Readonly\<T>: 将对象类型的所有属性变为可读
    • 4. Record\<K, T>: 创建一个对象类型
    • 5. Pick\<T, K>: 从对象类型中选取一组属性
    • 6. Omit\<T, K>: 从对象类型中排除指定的一组属性
    • 7. Extract\<T, U>:提取联合类型中并存的类型
    • 8. Exclude\<T, U>: 从一个联合类型中排除另一个联合类型的成员
    • 9. NonNullable\<T>: 排除类型中的null和undefined
    • 10. ReturnType\<T>: 获取函数的返回类型
    • 11. InstanceType\<T>: 获取构造函数的实例类型
    • 12. ThisType\<T>: 提供对上下文this的类型支持

TypeScript实用笔记(一):初始化、类型定义与函数使用
TypeScript实用笔记(二):类与接口详解
TypeScripttype实用笔记(三):泛型的使用 && 的12种工具类型的使用

一、理解

TypeScript中初始化使用function时,就需要直接确定接收参数的类型、返回值的类型。而泛型<T>的出现,则可以让参数和返回值的类型变得更加灵活。不再是初始化function时去确定类型,而是在调用该方法的时候传类型。

[注意:<T>这个T可以是任意字母,这里只是type首字母的缩写,省事儿就用了]

二、使用

1. 泛型函数

1.1 单一类型参数的泛型函数

  • 可以定义接受类型参数的函数
function identity<T>(arg: T): T {
    return arg;
}

const result1 = identity<number>(42); //指定类型为 number
const result2 = identity<string>("Hello"); //指定类型为 string

console.log(result1); //输出: 42
console.log(result2); //输出: Hello

1.2 泛型数组

//<T>中的T表示单一的类型。而 T[] 表示该类型的数组。因此,定义一个接受数组的泛型函数是完全合法的。但是不允许在<>中添加额外的,例如<T[]>是非法的
function identity<T>(arg: T[]): T[] {
    return arg;
}

const numberArray = identity<number>([1, 2, 3]); //T 被推断为 number
const stringArray = identity<string>(["Hello", "World"]); //T 被推断为 string
const numAndStr = identity<string | number>(["Hello", "World", 3]); // T 被推断为 string or number

console.log(numberArray); // 输出: [1, 2, 3]
console.log(stringArray); // 输出: ["Hello", "World"]

1.3 多个类型参数的泛型函数

  • 可以定义一个接受多个类型参数的函数。
function pair<K, V>(key: K, value: V): [K, V] {
    return [key, value];
}

const result = pair<string, number>("age", 30);
console.log(result); //输出: ['age', 30]

1.4 泛型约束

  • 可以为泛型参数添加约束,以确保其满足某个接口或类型的条件。
interface Lengthwise {
    length: number;
}

function logLength<T extends Lengthwise>(arg: T): void {
    console.log(arg.length);
}

logLength("Hello"); //正确,字符串有 length 属性
logLength([1, 2, 3]); //正确,数组有 length 属性

//logLength(123); //错误,数字没有 length 属性

1.5 默认类型参数

function createArray<T = number>(length: number): T[] {
    return new Array(length);
}

const numberArray = createArray(5); //默认类型为 number
const stringArray = createArray<string>(5); //指定类型为 string

console.log(numberArray); //输出: [ <5 empty items> ]
console.log(stringArray); //输出: [ <5 empty items> ]

1.6 使用泛型约束和函数重载

  • 可以接口泛型约束和函数重载来处理不同的输入类型
//定义一个接口,包含一个 name 属性
interface Named {
    name: string;
}

//定义一个泛型函数重载,接受一个 T 类型的参数并返回一个 string 类型的值
function greet<T extends Named>(value: T): string;
function greet(value: string): string;

//实现泛型函数,接受一个 T 类型的参数并返回一个 string 类型的值
function greet(value: any): string {
    if (typeof value === "string") {
        return `Hello, ${value}`;
    }
    return `Hello, ${value.name}`;
}

//调用 greet 函数,传入一个字符串,输出: Hello, Alice
console.log(greet("Alice")); //输出: Hello, Alice

//调用 greet 函数,传入一个包含 name 属性的对象,输出: Hello, Bob
console.log(greet({ name: "Bob" })); //输出: Hello, Bob

//调用 greet 函数,传入一个不包含 name 属性的对象会报错
//console.log(greet({ age: 30 })); //错误: 类型 '{ age: number; }' 不满足约束 'Named'

2. 泛型接口

2.1 单类型参数的泛型接口

  • 可以接受一个类型参数
interface GenericIdentityFn<T> {
	//"(arg: T)"的T为参数arg的类型。 "): T"的T为返回值的类型
    (arg: T): T;
}

const identity: GenericIdentityFn<number> = (arg: number): number => {
    return arg;
};

console.log(identity(42)); //输出: 42

//下面的代码为熟悉后简写的
interface GenericIdentityFn<T> {
    (arg: T): T;
}

const identity: GenericIdentityFn<number> = (arg) => arg;
console.log(identity(42)); //输出: 42

2.2 多类型参数的泛型接

  • 可以定义一个接受多个类型参数的接口
interface Pair<K, V> {
    key: K;
    value: V;
}

const pair: Pair<string, number> = { key: "age", value: 30 };
console.log(pair); // 输出: { key: 'age', value: 30 }

2.3 泛型约束

  • 可以为泛型添加约束,限制类型参数必须符合特定接口或类型
//定义一个接口 Lengthwise,包含一个 number 类型的 length 属性
interface Lengthwise {
    length: number;
}

//定义一个泛型接口 GenericArray,要求泛型 T 必须扩展自 Lengthwise
interface GenericArray<T extends Lengthwise> {
    items: T[]; //包含一个 T 类型的数组 items
    getLength(): number; //包含一个返回 number 类型的 getLength 方法
}

//定义一个泛型类 ArrayContainer,实现 GenericArray 接口
class ArrayContainer<T extends Lengthwise> implements GenericArray<T> {
    items: T[]; //定义 items 属性,类型为 T 类型的数组

    //构造函数,接受一个 T 类型的数组并赋值给 items 属性
    constructor(items: T[]) {
        this.items = items;
    }

    //实现 getLength 方法,返回 items 数组的长度
    getLength(): number {
        return this.items.length;
    }
}

//创建一个 ArrayContainer 实例,传入一个包含两个对象的数组,每个对象都有 length 属性
const container = new ArrayContainer([{ length: 5 }, { length: 10 }]);

//调用 getLength 方法并输出结果,输出: 2
console.log(container.getLength()); //输出: 2

2.4 默认类型参数

  • 可以为泛型接口定义默认类型
interface GenericIdentityFn<T = string> {
    (arg: T): T;
}

const myIdentity: GenericIdentityFn = (arg) => arg; // 默认 T 为 string
console.log(myIdentity("Hello")); // 输出: Hello

2.5 复杂类型

  • 可以使用复杂类型作为泛型参数,比如嵌套的接口或类型
interface Box<T> {
    content: T;
}

interface Item {
    name: string;
}

const itemBox: Box<Item> = { content: { name: "Widget" } };
console.log(itemBox.content.name); // 输出: Widget

3. 泛型类

3.1 单类型参数的泛型类

  • 这是最基本的泛型类定义,可以接受一个类型参数。
//定义一个泛型类 Box,接受类型参数 T
class Box<T> {
    private value: T; //使用类型参数 T 定义一个私有属性

    constructor(value: T) { //构造函数接收一个类型为 T 的参数
        this.value = value;
    }

    getValue(): T { //方法返回类型为 T 的值
        return this.value;
    }
}

//创建一个 Box 实例,指定类型为 number
const numberBox = new Box<number>(42);
console.log(numberBox.getValue()); //输出: 42

//创建一个 Box 实例,指定类型为 string
const stringBox = new Box<string>("Hello");
console.log(stringBox.getValue()); //输出: Hello

3.2 多个类型参数的泛型类

  • 可以定义一个接受多个类型参数的泛型类。
//定义一个泛型类 Pair,接受两个类型参数 K 和 V
class Pair<K, V> {
    private key: K; //属性 key 的类型为 K
    private value: V; //属性 value 的类型为 V

    constructor(key: K, value: V) { //构造函数接收两个参数
        this.key = key;
        this.value = value;
    }

    getKey(): K { //返回类型为 K 的 key
        return this.key;
    }

    getValue(): V { //返回类型为 V 的 value
        return this.value;
    }
}

//创建一个 Pair 实例,指定类型为 string 和 number
const pair = new Pair<string, number>("age", 30);
console.log(pair.getKey()); //输出: age
console.log(pair.getValue()); //输出: 30

3.3 泛型约束

  • 可以为泛型添加约束,以限制类型参数的类型。
//定义一个接口,约束具有 length 属性的类型
interface Lengthwise {
    length: number;
}

//定义一个泛型类,约束类型参数必须符合 Lengthwise 接口
class Container<T extends Lengthwise> {
    private items: T[]; //使用类型参数 T 定义一个数组属性

    constructor(items: T[]) {
        this.items = items;
    }

    getLength(): number { //返回 items 数组的长度
        return this.items.length;
    }
}

//创建一个 Container 实例,数组项必须具有 length 属性
const stringContainer = new Container<string>(["Hello", "World"]);
console.log(stringContainer.getLength()); //输出: 2

//const numberContainer = new Container<number>([1, 2, 3]); //错误:number 没有 length 属性

3.4 默认类型参数

  • 可以为泛型类定义默认类型参数。
//定义一个泛型类 Stack,默认类型为 number
class Stack<T = number> {
    private items: T[] = []; //使用类型参数 T 定义一个数组

    push(item: T): void { //方法接收类型为 T 的参数
        this.items.push(item);
    }

    pop(): T | undefined { //返回类型为 T 的元素或 undefined
        return this.items.pop();
    }
}

//创建 Stack 实例,使用默认类型 number
const numberStack = new Stack(); //不指定类型,默认为 number
numberStack.push(1);
console.log(numberStack.pop()); //输出: 1

//创建 Stack 实例,指定类型为 string
const stringStack = new Stack<string>();
stringStack.push("Hello");
console.log(stringStack.pop()); //输出: Hello

3.5 复杂类型

  • 可以使用复杂类型作为泛型参数,比如嵌套的接口或类型。
//定义一个接口 Item
interface Item {
    id: number;
    name: string;
}

//定义一个泛型类 Warehouse,接受 Item 类型的数组
class Warehouse<T extends Item> {
    private items: T[] = []; //定义一个数组来存储项目

    addItem(item: T): void { //添加项目
        this.items.push(item);
    }

    getItems(): T[] { //返回项目列表
        return this.items;
    }
}

//创建一个 Warehouse 实例,存储 Item 类型
const warehouse = new Warehouse<Item>();
warehouse.addItem({ id: 1, name: "Item 1" });
console.log(warehouse.getItems()); //输出: [{ id: 1, name: 'Item 1' }]

三、工具类型

1. Partial<T>: 将对象类型的所有属性变为可选

  • Partial将对象类型的所有属性变为可选。
interface User {
    id: number;
    name: string;
    age: number;
}

//使用 Partial 将 User 的属性变为可选
const partialUser: Partial<User> = {
    name: "Alice"
};

console.log(partialUser); //输出: { name: "Alice" }

//定义一个函数,接受一个 Partial<User> 类型的参数
function updateUser(user: Partial<User>) {
    //假设我们有一个现有的用户对象
    const existingUser: User = {
        id: 1,
        name: "Bob",
        age: 25
    };

    //使用 Object.assign 更新现有用户对象。Object.assign 方法将传入的部分更新信息合并到现有用户对象中,返回更新后的用户对象。
    const updatedUser = Object.assign({}, existingUser, user);
    return updatedUser;
}

//调用 updateUser 函数,传入部分更新的用户信息。如果定义function的时候,接收参数不是Partial<T>,那么这个位置使用的时候只传一个age会报错
const updatedUser = updateUser({ age: 30 });
console.log(updatedUser); //输出: { id: 1, name: "Bob", age: 30 }

//调用 updateUser 函数,传入完整的用户信息
const fullyUpdatedUser = updateUser({ id: 2, name: "Charlie", age: 35 });
console.log(fullyUpdatedUser); //输出: { id: 2, name: "Charlie", age: 35 }

2. Required<T>: 将对象类型的所有属性变为必选

  • Required将对象类型的所有属性变为必选。
//定义三个可选参数
interface User {
    id?: number;
    name?: string;
    age?: number;
}

//使用 Required 将 User 的所有属性变为必选
const completeUser: Required<User> = {
    id: 1,
    name: "Alice",
    age: 30
};

console.log(completeUser); //输出: { id: 1, name: "Alice", age: 30 }

//定义一个函数,接受一个 Required<User> 类型的参数
function printUser(user: Required<User>) {
    console.log(`ID: ${user.id}, Name: ${user.name}, Age: ${user.age}`);
}

//调用 printUser 函数,传入完整的用户信息
printUser({ id: 2, name: "Bob", age: 25 }); //输出: ID: 2, Name: Bob, Age: 25

//调用 printUser 函数,传入不完整的用户信息会报错
//printUser({ id: 3, name: "Charlie" }); //错误: 类型 '{ id: number; name: string; }' 不满足约束 'Required<User>'

3. Readonly<T>: 将对象类型的所有属性变为可读

  • Readonly将对象类型的所有属性变为可读。
interface User {
    id: number;
    name: string;
}

const readonlyUser: Readonly<User> = {
    id: 1,
    name: "Charlie"
};

//readonlyUser.name = "Dave"; //错误:无法分配到只读属性
console.log(readonlyUser); //输出: { id: 1, name: "Charlie" }

4. Record<K, T>: 创建一个对象类型

  • Record创建一个对象类型,K 是键的类型,T 是值的类型。
//----------value为定义的接口类型----------
//定义一个接口,表示用户信息
interface User {
    id: number;
    name: string;
    age: number;
}

//使用 Record 构造一个对象类型,其键为 string 类型,值为 User 类型
const userRecord: Record<string, User> = {
    "user1": { id: 1, name: "Alice", age: 30 },
    "user2": { id: 2, name: "Bob", age: 25 },
    "user3": { id: 3, name: "Charlie", age: 35 }
};


//----------key为定义的接口类型----------
type Role = "admin" | "user" | "guest";

//创建一个以 Role 为键,string 为值的对象。 因为key已经确定是Role,那UserRoles里面的key和Role中一样,不能多,也不能少
const userRoles: Record<Role, string> = {
    admin: "Admin",
    user: "User",
    guest: "Guest",
	player: "Player" //报错:对象字面量只能指定已知属性,并且“player”不在类型“Record<Role, string>”中
};

console.log(userRoles); //输出: { admin: 'Admin', user: 'User', guest: 'Guest' }

5. Pick<T, K>: 从对象类型中选取一组属性

  • Pick 从对象类型中选取一组属性。
interface User {
    id: number;
    name: string;
    age: number;
}

//使用 Pick 只选择 User 中的 id 和 name 属性
const pickedUser: Pick<User, "id" | "name"> = {
    id: 1,
    name: "Eve"
};

console.log(pickedUser); //输出: { id: 1, name: "Eve" }

6. Omit<T, K>: 从对象类型中排除指定的一组属性

  • Omit从对象类型中排除指定的一组属性。
interface User {
    id: number;
    name: string;
    age: number;
}

//使用 Omit 排除 age 属性
const omittedUser: Omit<User, "age"> = {
    id: 2,
    name: "Frank"
};

console.log(omittedUser); //输出: { id: 2, name: "Frank" }

7. Extract<T, U>:提取联合类型中并存的类型

  • Extract提取联合类型中并存的类型。
type Status = "success" | "error" | "pending";
type ErrorStatus = "error" | "fatal";

//提取 Status 中同时存在于 ErrorStatus 中的类型
type CommonStatus = Extract<Status, ErrorStatus>; //"error"

8. Exclude<T, U>: 从一个联合类型中排除另一个联合类型的成员

  • Exclude用于从一个联合类型中排除另一个联合类型的成员。
//定义一个联合类型 Status
type Status = "success" | "error" | "pending";

//定义一个联合类型 ExcludeStatus
type ExcludeStatus = "error" | "fatal";

//使用 Exclude 工具类型排除 Status 中属于 ExcludeStatus 的成员
type RemainingStatus = Exclude<Status, ExcludeStatus>; //"success" | "pending"

//示例函数,接受 RemainingStatus 类型的参数
function updateStatus(status: RemainingStatus) {
    console.log(`Status updated to: ${status}`);
}

//调用 updateStatus 函数,传入 "success"
updateStatus("success"); //输出: Status updated to: success

//调用 updateStatus 函数,传入 "pending"
updateStatus("pending"); //输出: Status updated to: pending

//调用 updateStatus 函数,传入 "error" 会报错
//updateStatus("error"); //错误: 类型 '"error"' 不满足约束 'RemainingStatus'

//调用 updateStatus 函数,传入 "fatal" 会报错
//updateStatus("fatal"); //错误: 类型 '"fatal"' 不满足约束 'RemainingStatus'

9. NonNullable<T>: 排除类型中的null和undefined

  • NonNullable 排除类型中的 nullundefined
//定义一个联合类型,包含 string、number、null 和 undefined
type NullableType = string | number | null | undefined;

//使用 NonNullable 工具类型排除 NullableType 中的 null 和 undefined
type NonNullableType = NonNullable<NullableType>; //string | number

//示例函数,接受 NonNullableType 类型的参数
function printValue(value: NonNullableType) {
    console.log(`Value: ${value}`);
}

//调用 printValue 函数,传入 string 类型的值
printValue("Hello"); //输出: Value: Hello

//调用 printValue 函数,传入 number 类型的值
printValue(42); //输出: Value: 42

//调用 printValue 函数,传入 null 会报错
//printValue(null); //错误: 类型 'null' 不满足约束 'NonNullableType'

//调用 printValue 函数,传入 undefined 会报错
//printValue(undefined); //错误: 类型 'undefined' 不满足约束 'NonNullableType'

10. ReturnType<T>: 获取函数的返回类型

  • ReturnType 获取函数的返回类型。
//定义一个函数 getUserId,返回一个 number 类型的值
function getUserId(): number {
    return 123;
}

//使用 ReturnType 获取 getUserId 函数的返回类型
type UserId = ReturnType<typeof getUserId>; //number

//定义一个函数 getUserName,返回一个 string 类型的值
function getUserName(): string {
    return "Alice";
}

//使用 ReturnType 获取 getUserName 函数的返回类型
type UserName = ReturnType<typeof getUserName>; //string

//示例函数,接受 UserId 类型的参数
function printUserId(id: UserId) {
    console.log(`User ID: ${id}`);
}

//示例函数,接受 UserName 类型的参数
function printUserName(name: UserName) {
    console.log(`User Name: ${name}`);
}

//调用 printUserId 函数,传入一个 number 类型的值
printUserId(123); //输出: User ID: 123

//调用 printUserName 函数,传入一个 string 类型的值
printUserName("Alice"); //输出: User Name: Alice

//调用 printUserId 函数,传入一个 string 类型的值会报错
//printUserId("123"); //错误: 类型 'string' 不满足约束 'number'

//调用 printUserName 函数,传入一个 number 类型的值会报错
//printUserName(123); //错误: 类型 'number' 不满足约束 'string'

11. InstanceType<T>: 获取构造函数的实例类型

  • InstanceType 获取构造函数的实例类型。
class User {
    constructor(public name: string) {}
}

//获取 User 类的实例类型
type UserInstance = InstanceType<typeof User>;

const user: UserInstance = new User("Alice");
console.log(user); //输出: User { name: "Alice" }

12. ThisType<T>: 提供对上下文this的类型支持

  • ThisType 提供对上下文 this 的类型支持(通常配合 object--noImplicitThis 编译选项使用)。
interface MyObject {
    count: number;
    increment(): void;
}

const obj: MyObject & ThisType<MyObject> = {
    count: 0,
    increment() {
        this.count++; //this 被推断为 MyObject
    }
};

obj.increment();
console.log(obj.count); //输出: 1

http://www.kler.cn/a/380388.html

相关文章:

  • 【Linux】从零开始使用多路转接IO --- epoll
  • 借助 Aspose.Words,使用 C# 从 Word 文档中删除页面
  • MySQL的约束和三大范式
  • Axure大屏可视化模板:赋能各行各业的数据展示与管理
  • PHP JSON 教程
  • 【初阶数据结构篇】链式结构二叉树(二叉链)的实现(感受递归暴力美学)
  • python代码主要实现了对供水网络的水质模拟,并对模拟结果进行一系列处理
  • ‌5G SSB(同步信号块)位于物理层‌
  • Python淘宝数据挖掘与词云图制作指南
  • Python 继承、多态、封装、抽象
  • 华为HarmonyOS打造开放、合规的广告生态 - 原生广告
  • JVM出现OOM错误排查
  • 类被加载到jvm后再被注册到Spring中
  • Java 教程简介
  • JqGird 动态生成列使用
  • django各个文件简单介绍
  • RabbitMQ交换机类型
  • C#代码生成器实现原理
  • w~大模型~合集19
  • 【JAVA】Java基础—Java开发环境搭建:安装JDK与IDE(如IntelliJ IDEA、Eclipse)
  • 临街矩阵乘以自己转置的含义
  • 气象大模型学习笔记
  • QT:QThread:重写run函数
  • HarmonyOS:UIAbility组件概述
  • k8s 上如何跑 Dolphins 模型
  • CentOS一次性安装 Nginx 的脚本指南