网站首页 > 资源文章 正文
大家好,我是yangyang.最近在用ts,今天整理记录一篇常用的基础知识并分享给大家.
类型级编程
TypeScript 中的类型级编程释放了无限可能,它利用语言强大的类型系统,直接在类型系统中执行复杂的计算、验证和转换。通过利用泛型、条件类型、映射类型等功能,开发者可以创建复杂的类型级抽象,从而执行约束、确保类型安全并提高代码的正确性。TypeScript 中的类型级编程使开发人员能够编写更健壮、可靠和可维护的代码,突破了静态类型语言的极限。
基本类型
typeScript 的内置原始类型,例如number, string, boolean, null, undefined, object, symbol, bigint.
类型别名
使用type关键字为现有类型创建别名,从而更容易阅读和重用。
//元组定义一个point类型别名
type Point = [number, number];
// 定义一个计算两点之间距离的函数
function calculateDistance(point1: Point, point2: Point): number {
const [x1, y1] = point1;
const [x2, y2] = point2;
const dx = x2 - x1;
const dy = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
const pointA: Point = [0, 0];
const pointB: Point = [3, 4];
const distance = calculateDistance(pointA, pointB);
console.log(distance);
接口
定义表示对象形状的结构类型。
// 定义一个表示具有最小年龄的用户的接口
interface User {
name: string;
age: number;
}
//定义一个类型级别的约束,确保用户的年龄至少为18岁
type AdultUser<T extends User> = T['age'] extends number ? (T['age'] extends infer Age ? Age extends number ? Age extends number & (Age >= 18) ? T : never : never : never : never);
/**
*这段代码定义了一个名为 createAdultUser 的函数,它具有以下含义:
* <T extends User> 是一个泛型类型参数,它约束了传入的参数类型必须符合 User 接口。
* (user: AdultUser<T>) 是函数的参数列表,其中 user 是一个参数,它的类型是 AdultUser<T>,即符合成年用户约束的类型。
* : AdultUser<T> 是函数的返回类型注解,它表示函数返回的值的类型是 AdultUser<T>,即满足成年用户约束的类型。
* 函数的功能非常简单:它接受一个满足成年用户约束的对象作为参数,并将该对象直接返回。换句话说,它不对传入的对象进行任何处理或修改,只是将其原样返回。
*这个函数的目的可能是为了提供一个通用的方式来创建成年用户对象,同时保持类型的一致性。通过使用泛型类型参数,它可以适用于不同类型的用户对象,只要这些对象满足成年用户的约束。
*/
function createAdultUser<T extends User>(user: AdultUser<T>): AdultUser<T> {
return user;
}
const validUser = createAdultUser({ name: 'yang', age: 25 });
const invalidUser = createAdultUser({ name: 'wan', age: 17 });
并集和交集
|使用联合类型和交集类型将多种类型合并为一种类型&。
type Square = {
sideLength: number;
};
type Circle = {
radius: number;
};
type Shape = Square | Circle;
const square: Shape = {
sideLength: 5
};
const circle: Shape = {
radius: 3
};
类型保护装置
使用类型谓词(例如,value is SomeType)来细化条件语句中的类型。
//您可以使用typeof运算符在运行时检查变量的类型。
function isNumber(x: any): x is number {
return typeof x === "number";
}
const value2: unknown = 42;
if (typeof value2 === 'number') {
console.log('The value is a number');
} else if (typeof value2 === 'string') {
console.log('The value is a string');
} else {
console.log('The value is of an unknown type');
}
const value: number | string = 42;
if (isNumber(value)) {
console.log(value.toFixed(2));
}
//instanceof运算符用于检查对象是否是特定类或构造函数的实例。
class Dog {
breed: string;
constructor(breed: string) {
this.breed = breed;
}
}
function isDog(x: any): x is Dog {
return x instanceof Dog;
}
const pet: Dog | Cat = new Dog("Labrador");
if (isDog(pet)) {
console.log(pet.breed);
}
泛型
编写通过参数化来操作不同类型的可重用代码。
type Keys<T> = keyof T; // <---- <T>
interface Person {
name: string;
age: number;
}
type PersonKeys = Keys<Person>; // PersonKeys is "name" | "age"
映射类型
Partial使用、Required、Readonly等映射类型将现有类型转换为新类型。
TypeScript 中的映射类型是一项强大的功能,允许您通过转换现有类型的属性来创建新类型。当您需要基于现有类型的结构创建新类型(例如将所有属性转换为可选或只读)时,映射类型特别有用。
映射类型的语法涉及迭代现有类型的键并应用转换来创建新类型。
(映射类型和索引类型在语法上相似,但请始终记住映射类型中有关键字“in”)
这是映射类型的基本示例:
type Person = {
name: string;
age: number;
};
// 创建一个新类型,其中所有属性都是可选的
type PartialPerson = {
[Key in keyof Person]?: Person[Key]; // <<-- beware of the keyword 'in'
};
// Usage
const partialPerson: PartialPerson = {};
在这个例子中:
- keyof Person检索类型的键Person,它们是"name"和"age"。
- [Key in keyof Person]迭代每个键。
- Person[Key]访问每个属性的类型。
映射类型支持各种转换,包括:
- 使属性可选:
type PartialPerson = {
[Key in keyof Person]?: Person[Key];
};
- 将属性设置为只读:
type ReadonlyPerson = {
readonly [Key in keyof Person]: Person[Key];
};
- 使属性可为空:
type NullablePerson = {
[Key in keyof Person]: Person[Key] | null;
};
- 删除属性:
type AgelessPerson = {
[Key in keyof Person as Exclude<Key, "age">]: Person[Key];
};
映射类型具有高度通用性,可用于基于现有类型的复杂转换来创建新类型,从而提供了在 TypeScript 中定义类型变体的灵活方法。
条件类型
类型内的条件表达式,用于根据条件确定结果类型。
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
T extends Function ? "function" :
"object";
type T0 = TypeName<string>; // "string"
type T1 = TypeName<"hello">; // "string"
type T2 = TypeName<42>; // "number"
type T3 = TypeName<true>; // "boolean"
type T4 = TypeName<undefined>; // "undefined"
type T5 = TypeName<() => void>; // "function"
type T6 = TypeName<string[]>; // "object"
递归类型
定义引用自身的类型,从而能够创建递归数据结构。
interface TreeNode<T> {
value: T;
left?: TreeNode<T>;
right?: TreeNode<T>;
}
const tree: TreeNode<number> = {
value: 1,
left: {
value: 2,
left: {
value: 4
},
right: {
value: 5
}
},
right: {
value: 3
}
};
指数类型
keyof使用索引类型 ( , )访问和操作对象的属性[]。
(映射类型和索引类型在语法上相似,但请始终记住映射类型中有关键字“in”)。
//字符串索引签名允许您定义通过字符串访问属性的类型 // string keys on an object.
interface Dictionary<T> {
[key: string]: T;
}
const dict: Dictionary<number> = {
"a": 1,
"b": 2,
"c": 3
};
console.log(dict["a"]);
// 数字索引签名允许您定义通过数字访问元素的类型 // numeric keys on an array-like object.
interface NumericArray {
[index: number]: number;
}
const arr: NumericArray = [1, 2, 3];
console.log(arr[0]);
类型断言
TypeScript 中的类型断言是一种告诉编译器将值视为特定类型的方法,无论其推断类型如何。
let someValue: any = "hello";
let strLength: number = (<string>someValue).length;
let someValue: any = "hello";
let strLength: number = (someValue as string).length;
模板文字类型
它们允许您通过使用模板字符串语法连接或转换字符串文字类型来创建新类型。
使用模板文字类型,您可以在类型级别执行字符串操作,从而使您能够创建更具表现力和更精确的类型定义。
type Greeting = "Hello, " | "Hi, ";
type Name = "Tom" | "Bob";
type PersonalizedGreeting = `${Greeting}${Name}`; // "Hello, Tom" | "Hello, Bob" | "Hi, Tom" | "Hi, Bob"
Discriminated Unions
使用公共判别属性来区分联合类型的成员。
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
function area(shape: Shape): number {
switch (shape.kind) {
case "square":
return shape.size * shape.size;
case "rectangle":
return shape.width * shape.height;
case "circle":
return Math.PI * shape.radius ** 2;
}
}
类型查询
使用类型查询(例如,typeof、keyof、infer)检查和提取有关类型的信息。
TypeScript 中的类型查询是引用代码库中定义的类型的表达式。它们允许您将变量、属性或函数参数的类型提取为类型文字。
当您需要动态获取特定实体的类型时,类型查询非常有用,尤其是在使用复杂或泛型类型时。
以下是使用类型查询的方法:
- 变量类型查询: 您可以使用类型查询来引用变量的类型。
let x = { a: 1, b: "hello" };
// Type of 'x' is inferred as { a: number, b: string }
type XType = typeof x;
- 属性类型查询: 类型查询可用于引用对象中属性的类型。
type Person = {
name: string;
age: number;
};
//'name'的类型被推断为字符串
type NameType = Person["name"];
- 函数参数类型查询: 您可以使用类型查询来引用函数参数的类型。
function greet(name: string) {
console.log("Hello, " + name);
}
// 在'greet'函数中,'name'参数的类型被推断为字符串
type NameType = Parameters<typeof greet>[0];
- 使用类和接口进行类型查询: 类型查询还可以引用类和接口中定义的类型。
interface Circle {
radius: number;
area(): number;
}
// 'Circle'接口中'area'方法的类型
type AreaFunction = Circle["area"];
- 带推断的类型查询 类型查询 由 TypeScript 编译器静态评估,这意味着它们在编译过程中解析,不会产生任何运行时影响。它们提供了一种强大的机制,用于在代码库中提取和重用类型信息。
type ArrayElementType<T> = T extends (infer U)[] ? U : never;
type StringArray = Array<string>;
type NumberArray = Array<number>;
type ElementTypeOfStringArray = ArrayElementType<StringArray>; // ElementTypeOfStringArray is inferred as 'string'
type ElementTypeOfNumberArray = ArrayElementType<NumberArray>; // ElementTypeOfNumberArray is inferred as 'number'
/*
在这个例子中,ArrayElementType条件类型接受一个泛型类型T。它检查T是否扩展了一个数组类型(infer U)[]。如果是的话,它使用infer将数组元素的类型赋值给类型变量U。否则,它返回never.
*/
- 使用 keyof 进行类型查询TypeScript 中的 关键字keyof是一个强大的运算符,用于生成对象类型的所有已知、可枚举属性键的联合类型。它允许您将对象的键提取为字符串或数字文字,创建这些键的联合,然后您可以在各种上下文中使用该联合,例如索引或创建新类型。
interface Person {
name: string;
age: number;
address: string;
}
type PersonKeys = keyof Person;
// PersonKeys is now "name" | "age" | "address"
幻影类型(Phantom Types)
幻像类型是一种类型级编程技术,用于在编译时强制执行某些约束或不变量。它们涉及使用不直接参与运行时行为但仅用于类型检查目的的类型参数。幻像类型通常用于跟踪类型系统内的信息或状态。
// Phantom type representing a status
interface Status<T> {}
// Phantom type representing "active" status
interface Active extends Status<"active"> {}
// Phantom type representing "inactive" status
interface Inactive extends Status<"inactive"> {}
// User type with a phantom type parameter representing status
interface User<StatusType extends Status<any>> {
id: number;
name: string;
status: StatusType;
}
// Function to activate a user
function activateUser(user: User<Inactive>): User<Active> {
return { ...user, status: {} as Active };
}
// Function to deactivate a user
function deactivateUser(user: User<Active>): User<Inactive> {
return { ...user, status: {} as Inactive };
}
const inactiveUser: User<Inactive> = { id: 1, name: "John", status: {} as Inactive };
const activeUser: User<Active> = activateUser(inactiveUser);
const deactivatedUser: User<Inactive> = deactivateUser(activeUser);
这些元素为 TypeScript 中的类型级编程提供了强大的基础,使开发人员能够表达和实施复杂的约束、设计健壮的 API,并实现更安全、更可维护的代码库。
示例:类型级别添加
// Phantom type representing a number
interface Num<T extends number> {}
// Type-level addition function
type Add<A extends number, B extends number> =
A extends 0
? B
: Add<
Num<A extends infer N ? N extends number ? N - 1 : never : never>,
Num<B extends infer N ? N extends number ? N + 1 : never : never>
>;
// Example usage
type Result = Add<2, 3>; // Result is 5
- 我们定义一个幻像类型Num<T>来表示一个数字。
- 我们定义了一个类型级加法函数Add<A, B>。它是一个递归函数,从第一个数字 ( A) 中减去 1,然后向第二个数字 ( B) 加 1,直到第一个数字变为 0。这是使用条件类型和递归完成的。
- 所有递归操作完成后,加法的结果表示为幻数的类型。
猜你喜欢
- 2024-10-19 Flask框架学习之环境配置(flask框架安装与配置)
- 2024-10-19 《神奇的VBA》编程:禁止修改Excel工作表名称
- 2024-10-19 Python虚拟环境实用指南(python虚拟环境管理工具)
- 2024-10-19 TS学习笔记十:装饰器及三斜线指令
- 2024-10-19 「NS」关于switch使用中会出现的一些疑难问题的解答
- 2024-10-19 「博文连载」ARM GIC(二)中断术语
- 2024-10-19 学习VBA,报表做到飞 第五章 事件篇 5.8 Worksheet_Deactivate事件
- 2024-10-19 Linux 中如何启用和禁用网卡(linux禁用无线网卡)
- 2024-10-19 Excel-VBA对象、属性、方法和事件(5)
- 2024-10-19 Excel-VBA对象、属性、方法和事件(4)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- 电脑显示器花屏 (79)
- 403 forbidden (65)
- linux怎么查看系统版本 (54)
- 补码运算 (63)
- 缓存服务器 (61)
- 定时重启 (59)
- plsql developer (73)
- 对话框打开时命令无法执行 (61)
- excel数据透视表 (72)
- oracle认证 (56)
- 网页不能复制 (84)
- photoshop外挂滤镜 (58)
- 网页无法复制粘贴 (55)
- vmware workstation 7 1 3 (78)
- jdk 64位下载 (65)
- phpstudy 2013 (66)
- 卡通形象生成 (55)
- psd模板免费下载 (67)
- shift (58)
- localhost打不开 (58)
- 检测代理服务器设置 (55)
- frequency (66)
- indesign教程 (55)
- 运行命令大全 (61)
- ping exe (64)
本文暂时没有评论,来添加一个吧(●'◡'●)