-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
在 TypeScript 中,使用 Omit 和将属性类型设为 never 虽然都能达到“不使用某个属性”的目的,但它们的底层逻辑、类型表现以及适用场景有本质的区别。
简单总结:
Omit是物理上的**“删除”**:该属性在类型中彻底不存在了。never是逻辑上的**“禁用”**:该属性还在,但无法给它赋值(通常用于互斥场景)。
1. 使用 Omit 排除属性
这是最标准、最常用的方法。它会生成一个新的类型,完全移除指定的键。
用法
interface User {
name: string;
email: string;
adminToken: string;
}
// 彻底移除 adminToken
type PublicUser = Omit<User, 'adminToken'>;
/*
PublicUser 的结构等同于:
{
name: string;
email: string;
}
*/表现
- 赋值检查:如果在对象字面量中包含该属性,会报错(Object literal may only specify known properties)。
- 访问检查:尝试访问该属性(
user.adminToken)会直接报错,因为属性不存在。 - IntelliSense:代码提示中不会出现该属性。
2. 使用 never 排除属性
这种方式通常保留属性名,但将其类型设为 never(通常配合可选修饰符 ?),表示“这个属性不应该有值”。
用法
interface User {
name: string;
email: string;
// 将 adminToken 设为可选且为 never
adminToken?: never;
}
const user1: User = {
name: "Xiaomei",
email: "test@example.com"
// ✅ 合法:不写 adminToken
};
const user2: User = {
name: "Xiaomei",
email: "test@example.com",
// ❌ 报错:Type 'string' is not assignable to type 'never'.
adminToken: "123"
};表现
- 赋值检查:你可以写这个属性名,但不能给它赋任何值(除了
undefined)。 - 访问检查:访问该属性是合法的,但得到的类型是
undefined。 - 类型结构:该属性依然存在于
keyof User中。
3. 核心区别对比
| 维度 | Omit (删除) | never (禁用) |
|---|---|---|
| 属性是否存在 | 不存在。keyof T 中不再包含该键。 |
存在。keyof T 仍包含该键。 |
| 代码提示 | 不会提示该属性。 | 会提示该属性,但类型显示为 never。 |
| 访问属性 | 报错:Property does not exist。 |
允许访问,但通常只能得到 undefined。 |
| 主要用途 | 裁剪类型,生成子集(DTO、Props)。 | 互斥类型(XOR),禁止某些属性组合。 |
4. 什么时候用哪个?
场景 A:只需要一部分数据(用 Omit)
如果你从后端获取了一个大对象,但前端组件只需要其中的一部分,或者你要把数据传给一个不应该知道 id 或 password 的函数。
请使用 Omit。
// 这里的 props 不需要 id,因为是新建用户
type CreateUserProps = Omit<User, 'id'>;场景 B:属性互斥(用 never)
这是 never 最强大的场景。假设一个组件,要么接受 text,要么接受 children,但不能同时接受。
如果用 Omit 很难表达“二选一”的关系,但用 never 可以实现 Discriminated Unions(可辨识联合) 的变体:
// 方案:使用 never 实现互斥 (XOR)
type TextProps = {
text: string;
children?: never; // ⛔️ 禁止传 children
};
type ChildrenProps = {
text?: never; // ⛔️ 禁止传 text
children: React.ReactNode;
};
type ButtonProps = TextProps | ChildrenProps;
// ✅ 合法
const b1: ButtonProps = { text: "Click me" };
const b2: ButtonProps = { children: <span>Click me</span> };
// ❌ 报错:不能同时存在
const b3: ButtonProps = {
text: "Click",
children: <span>Me</span>
};
// 报错原因:类型不能同时满足 TextProps (children必须是undefined) 和 ChildrenProps (text必须是undefined)总结
- 如果你只是想**“清理”**类型,让它变干净,用
Omit。 - 如果你是想**“限制”**类型,防止用户同时传递冲突的属性,用
never(配合联合类型)。