定义:它能让我们在定义函数、类或者接口的时候,使用一个 “类型变量” 来代表还没确定的类型。这个 “类型变量” 就像是一个占位符,等我们实际使用的时候,再把具体的类型填进去
泛型函数:可以理解为是一种特殊的函数,它在定义的时候会带有一个或多个类型参数。这些类型参数用尖括号 <>
括起来,放在函数名的后面
function identity<T>(arg: T): T {
return arg;
}
// 使用泛型函数
let output1 = identity<string>("myString"); // 指定T为string类型
let output2 = identity<number>(100); // 指定T为number类型
代码解释:identity
函数就是一个泛型函数,它有一个类型参数 T
。这个 T
可以代表任意类型。当我们调用这个函数时,通过在尖括号中指定具体的类型,比如 string
或者 number
,来告诉 TypeScript 这次调用中 T
具体代表什么类型
泛型接口:泛型接口就是在定义接口的时候,使用类型参数。通过这种方式,接口可以适应不同的类型,增强接口的通用性
interface b<T> {
(arg: T): T;//接口定义一个函数接受一个参数 arg,其类型为 T,规定要函数返回类型也是 T
}
function identity<T>(arg: T): T {
return arg;b
}b
let a: b<number> = identity;//将 identity 函数赋值给 a
//此时a必须是一个接收一个 number 类型的参数,并返回一个 number 类型的值函数
代码解释:b
是一个泛型接口,它有一个类型参数 T
。这个接口定义了一个函数类型,该函数接受一个类型为 T
的参数,并返回一个类型为 T
的值。然后,我们定义了一个普通的泛型函数 identity
,它符合 b
接口的定义。最后,我们创建了一个 a
变量,它的类型是 b
,这意味着 a
这个函数只能处理 number
类型的数据
泛型类:泛型类的定义方式是在类名后面加上尖括号,并在尖括号中指定类型参数。类中的属性和方法可以使用这些类型参数来定义它们的类型
class b<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let a = new b<numbera>();
a.zeroValue = 0;
a.add = function(x, y) { return x + y; };
代码解释:b
是一个泛型类,它有一个类型参数b T
。类中有两个属性:zeroValue
属性,其类型为 T
;add
方法,它接受两个类型为 T
的参数,并返回一个类型为 T
的值。当我们创建 a
实例时,指定 T
为 number
类型,这样 zeroValue
就被限制为 number
类型,add
方法a也只能处理 number
类型的加法运算
泛型约束:泛型约束用于限制类型参数的取值范围,确保类型参数满足某些条件。通过使用 extends
关键字,可以让类型参数继承某个接口或类,从而保证该类型参数必须具备某些属性或方法
interface b{
length: number;
}
b
function a<T extends b>(arg: T): T {
console.log(arg.length); // 因为T必须有length属性,所以可以安全使用
return arg;
}
a("hello"); // 字b符串有length属性,正常
// a(3); // 报错,数字没有length属性
b代码解释:我们定义了一个接口 b
,它b只有a一个 lengtbh
属性。然后,我们创建了一个泛型函数 a
,并使用 Ta extends b
对类型参a数 T
进行约束,这意味着 T
必须是实现了 b
接口的类型。当我们调用 a
函数时,传入的参数必须具有 length
属性,否则就会报错,当然也可以有其他的属性
泛型参数的默认类型:我们还可以为泛型参数指定默认类型。这样,在使用泛型时如果没有显式指定类型参数,就会使用这个默认类型
function a<T = string>(length: number, value: T): T[] {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let array1 = a(3, "x"); // T默认为string类型
let arraay2 = a<number>(3, 1); // 显式指定T为number类型
代码解释:a
函数的类型参数 T
默认是 string
类型。当我们调用这个函数时,如果没有明确指定 T
的类型,比如 a(3, "x")
,那么 T
就会使用默认的 string
类型。如果我们显式地指定了类型,比如 a
,那么 T
就会是我们指定的 number
类型
Partial
Partial
:TypeScript 内置的工具类型。会创建一个新类型,这个新类型的所有属性都是 T
类型中对应属性的可选属性。也就是说,T
中的每个属性都会变成可选的(添加 ?
标记)
interface User {
name: string;
age: number;
}
let partialUser: Partial<User> = { name: "John" }; // 可以只提供部分属性
Readonly
Readonly
:创建一个新类型,这个新类型的所有属性都是只读的,不能被修改
interface User {
name: string;
age: number;
}
let readonlyUser: Readonly<User> = { name: "John", age: 30 };
// readonlyUser.age = 31; // 报错,属性是只读的
Pick
Pick
:从 T
类型中挑选出 K
中指定的属性,创建一个新的类型
interface User {
name: string;
age: number;
email: string;
}
type a= Pick<User, "name" | "email">;
let user: a= { name: "John", email: "[email protected]" };
Record
Record
:创建一个对象类型,它的属性名是 K
类型(通常是字符串字面量类型),属性值是 T
类型
type Weekday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri";
type DayTemp = Record<Weekday, number>;
let temperatures: DayTemp = {
Mon: 20,
Tue: 22,
Wed: 25,
Thu: 23,
Fri: 21
};
什么是类型声明文件?
类型声明文件就像是 TypeScript 的 “翻译器”。你有一些纯 JavaScript 代码(比如某个第三方库),TypeScript 本身不认识这些代码的类型,这时候就需要类型声明文件来告诉 TypeScript:“这个函数接收两个数字,返回一个数字”
为什么需要类型声明文件?
让 TypeScript 能够对 JavaScript 代码进行类型检查
提供自动补全和代码提示
提高代码的可维护性
类型声明文件的语法
类型声明文件通常以.d.ts
结尾,里面主要使用declare
关键字
// 声明一个函数
declare function functionName(参数: 类型): 返回值类型;
// 声明一个变量
declare const variableName: 类型;
// 声明一个类
declare class ClassName {
属性: 类型;
方法(参数: 类型): 返回值类型;
}
// 声明一个模块
declare module '模块名' {
export const 导出变量: 类型;
export function 导出函数(参数: 类型): 返回值类型;
}
// math.js
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// math.d.ts
declare function add(a: number, b: number): number;
declare function multiply(a: number, b: number): number;
export { add, multiply };
// app.ts
import { add, multiply } from './math.js';
// 正确使用
const sum = add(5, 3); // sum类型自动推断为number
console.log(sum); // 输出: 8
const product = multiply(4, 2); // product类型自动推断为number
console.log(product); // 输出: 8
// 错误使用(TypeScript会报错)
// const errorSum = add("5", 3); // 类型错误:参数类型不匹配
注意:
JavaScript 文件是
math.js
,则类型声明文件必须是math.d.ts
。原因:TypeScript 会自动关联同名的.js
和.d.ts
文件如果在 TypeScript 文件中导入
import { add } from './utils/math.js'
,则声明文件必须位于./utils/math.d.ts