Ts中的继承
使用接口扩展(extends)
适用场景:当原类型是接口或需要通过接口继承时
实现方式:
用 extends 关键字继承原接口
直接添加新属性的定义
ts
interface BaseType {
id: number;
name: string;
}
// 继承并添加新属性
interface ExtendedType extends BaseType {
age: number; // 新增必选属性
email?: string; // 新增可选属性
}
// 使用示例
const user: ExtendedType = {
id: 1,
name: "Alice",
age: 30
};
特点:
类型安全:编译时会严格检查所有必填属性
支持多继承:例如 interface A extends B, C
补充技巧
声明合并
如果是全局接口,可以通过重复声明自动合并属性:
ts
interface Car { speed: number; }
interface Car { color: string; } // 自动合并
const myCar: Car = { speed: 120, color: "red" }; // 合法
注意:仅适用于全局或模块级作用域
覆盖属性类型
在继承时可以重写父类型属性(需保持类型兼容性)
ts
interface Animal { legs: number; }
interface Spider extends Animal {
legs: 8; // 覆盖为字面量类型
}
动态扩展(索引签名)
如果需要运行时动态添加属性,可在接口中定义索引签名:
ts
interface DynamicObject {
[key: string]: any;
baseProp: string;
}
const obj: DynamicObject = { baseProp: "test" };
obj.newProp = 123; // 允许动态添加
代价:会牺牲部分类型安全性
使用类型别名交叉类型(&)
适用场景:当原类型是 type 或需要更灵活的类型操作时
通过 & 合并原类型和新属性
ts
type BaseType = {
id: number;
name: string;
};
// 继承并扩展
type ExtendedType = BaseType & {
age: number;
address?: string;
};
// 使用示例
const product: ExtendedType = {
id: 100,
name: "Laptop",
age: 2 // 产品上市年限
};
特点:
灵活性:可结合联合类型、条件类型等高级特性
适用于复杂类型操作:例如动态生成类型
泛型
(1)通过作用理解泛型
用来弥补any没有语法提示和报错的缺点。
最开始不指定类型,后面根据我们传入的类型确定类型。
三、泛型约束
默认情况下我们可以指定泛型为任意类型,但是有些情况下我们需要指定的类型满足某些条件后才能指定
那么这个时候我们就可以使用泛型约束。
typescript 代码解读复制代码// 需求: 要求指定的泛型类型必须有Length属性才可以
泛型(Generics)详解
泛型是 TypeScript 中非常重要的特性,它允许我们创建可重用的组件,这些组件可以支持多种类型而不是单一类型。
一、泛型基础
1. 泛型函数
typescript
// 普通函数只能返回一种类型
function identity(arg: number): number {
return arg;
}
// 泛型函数可以适用于多种类型
function identity<T>(arg: T): T {
return arg;
}
// 使用方式1:显式指定类型
let output = identity<string>("myString");
// 使用方式2:类型推断
let output2 = identity("myString"); // 自动推断为string类型
2. 泛型接口
typescript
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
3. 泛型类
typescript
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; };
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };
二、泛型约束
1. 基本约束
typescript
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在编译器知道arg有length属性
return arg;
}
loggingIdentity(3); // 错误,数字没有length属性
loggingIdentity({length: 10, value: 3}); // 正确
2. 在泛型约束中使用类型参数
typescript
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // 正确
getProperty(x, "m"); // 错误: m不是x的属性
三、泛型工具类型
TypeScript 提供了一些内置的泛型工具类型:
1. Partial<T> - 将所有属性变为可选
typescript
interface Todo {
title: string;
description: string;
}
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return { ...todo, ...fieldsToUpdate };
}
const todo1 = {
title: "organize desk",
description: "clear clutter"
};
const todo2 = updateTodo(todo1, {
description: "throw out trash"
});
2. Required<T> - 将所有属性变为必选
typescript
interface Props {
a?: number;
b?: string;
}
const obj: Props = { a: 5 };
const obj2: Required<Props> = { a: 5 }; // 错误: 缺少属性b
3. Readonly<T> - 将所有属性变为只读
typescript
interface Todo {
title: string;
}
const todo: Readonly<Todo> = {
title: "Delete inactive users"
};
todo.title = "Hello"; // 错误: 无法分配到"title",因为它是只读属性
4. Record<K,T> - 构造一个对象类型,其属性键为K,属性值为T
typescript
interface CatInfo {
age: number;
breed: string;
}
type CatName = "miffy" | "boris" | "mordred";
const cats: Record<CatName, CatInfo> = {
miffy: { age: 10, breed: "Persian" },
boris: { age: 5, breed: "Maine Coon" },
mordred: { age: 16, breed: "British Shorthair" }
};
5. Pick<T,K> - 从T中选取一组属性K
typescript
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Clean room",
completed: false
};
6. Omit<T,K> - 从T中排除一组属性K
typescript
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Omit<Todo, "description">;
const todo: TodoPreview = {
title: "Clean room",
completed: false
};
7. Exclude<T,U> - 从T中排除可以赋值给U的类型
typescript
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T1 = Exclude<string | number | (() => void), Function>; // string | number
8. Extract<T,U> - 从T中提取可以赋值给U的类型
typescript
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
type T1 = Extract<string | number | (() => void), Function>; // () => void
9. NonNullable<T> - 从T中排除null和undefined
typescript
type T0 = NonNullable<string | number | undefined>; // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]
10. ReturnType<T> - 获取函数类型的返回类型
typescript
type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<<T>() => T>; // unknown
11. Parameters<T> - 获取函数类型的参数类型
typescript
declare function f1(arg: { a: number; b: string }): void;
type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [s: string]
type T2 = Parameters<<T>(arg: T) => T>; // [arg: unknown]
type T3 = Parameters<typeof f1>; // [arg: { a: number; b: string }]
四、高级泛型技巧
1. 条件类型
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<"a">; // "string"
type T2 = TypeName<true>; // "boolean"
type T3 = TypeName<() => void>; // "function"
type T4 = TypeName<string[]>; // "object"
2. 分布式条件类型
typescript
type BoxedValue<T> = { value: T };
type BoxedArray<T> = { array: T[] };
type Boxed<T> = T extends any[] ? BoxedArray<T[number]> : BoxedValue<T>;
type T1 = Boxed<string>; // { value: string }
type T2 = Boxed<number[]>; // { array: number[] }
type T3 = Boxed<string | number[]>; // BoxedValue<string> | BoxedArray<number>
3. 类型推断(infer)
typescript
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type Unpacked<T> =
T extends (infer U)[] ? U :
T extends (...args: any[]) => infer U ? U :
T extends Promise<infer U> ? U :
T;
type T0 = Unpacked<string>; // string
type T1 = Unpacked<string[]>; // string
type T2 = Unpacked<() => string>; // string
type T3 = Unpacked<Promise<string>>; // string
type T4 = Unpacked<Promise<string>[]>; // Promise<string>
type T5 = Unpacked<Unpacked<Promise<string>[]>>; // string
4. 映射类型
typescript
type Keys = 'option1' | 'option2';
type Flags = { [K in Keys]: boolean };
// 等同于
type Flags = {
option1: boolean;
option2: boolean;
}
5. 键重映射(as)
typescript
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
interface Person {
name: string;
age: number;
location: string;
}
type LazyPerson = Getters<Person>;
// 等同于
// type LazyPerson = {
// getName: () => string;
// getAge: () => number;
// getLocation: () => string;
// }
五、实际应用示例
1. 泛型React组件
typescript
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
function List<T>(props: ListProps<T>) {
return (
<div>
{props.items.map(props.renderItem)}
</div>
);
}
// 使用
<List<number>
items={[1, 2, 3]}
renderItem={(item) => <div key={item}>{item}</div>}
/>
2. API响应类型
typescript
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
async function fetchUser(): Promise<ApiResponse<User>> {
const response = await fetch('/api/user');
return response.json();
}
3. 高阶函数
typescript
function debounce<F extends (...args: any[]) => any>(
func: F,
delay: number
): (...args: Parameters<F>) => void {
let timeoutId: ReturnType<typeof setTimeout>;
return function(this: any, ...args: Parameters<F>) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// 使用
const debouncedLog = debounce(console.log, 300);
debouncedLog("Hello, world!");
总结
TypeScript 泛型提供了强大的类型抽象能力,可以:
- 创建可重用的组件,支持多种类型
- 保持类型安全,避免使用 any 类型
- 利用类型推断减少冗余代码
- 通过约束控制类型参数的范围
- 使用工具类型简化常见类型转换
掌握泛型可以显著提高 TypeScript 代码的质量和可维护性,特别是在构建大型应用程序或库时。