从类型中排除属性
Posted
技术标签:
【中文标题】从类型中排除属性【英文标题】:Exclude property from type 【发布时间】:2018-06-21 07:22:33 【问题描述】:我想从类型中排除一个属性。我该怎么做?
例如我有
interface XYZ
x: number;
y: number;
z: number;
我想排除属性 z
来获取
type XY = x: number, y: number ;
【问题讨论】:
【参考方案1】:我发现solution 声明了一些变量并使用扩展运算符来推断类型:
interface XYZ
x: number;
y: number;
z: number;
declare var z, ...xy : XYZ;
type XY = typeof xy; // x: number; y: number;
它有效,但我很高兴看到更好的解决方案。
【讨论】:
这是一个很棒的 2.8 之前的解决方案。typeof
是 typescript 中被低估的功能之一。
聪明,我喜欢 :)! (对于 2.8 之前的版本)
如何在结果中添加带有类型字符串的 z
@user602291, type Smth = XY & z: string ;
?
这个非常适合旧版本的打字稿。我无法获得适用于 2.3 的公认答案,但这个答案很好。【参考方案2】:
对于 TypeScript 3.5 或更高版本
在 TypeScript 3.5 中,Omit
类型被添加到标准库中。请参阅下面的示例了解如何使用它。
对于低于 3.5 的 TypeScript 版本
在 TypeScript 2.8 中,Exclude
类型被添加到标准库中,这使得省略类型可以简单地写成:
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
对于低于 2.8 的 TypeScript 版本
您不能在低于 2.8 的版本中使用 Exclude
类型,但您可以创建一个替换它以使用与上述相同的定义。不过这种替换只对字符串类型有效,所以不如Exclude
强大。
// Functionally the same as Exclude, but for strings only.
type Diff<T extends string, U extends string> = ([P in T]: P & [P in U]: never & [x: string]: never )[T]
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>
以及该类型的使用示例:
interface Test
a: string;
b: number;
c: boolean;
// Omit a single property:
type OmitA = Omit<Test, "a">; // Equivalent to: b: number, c: boolean
// Or, to omit multiple properties:
type OmitAB = Omit<Test, "a"|"b">; // Equivalent to: c: boolean
【讨论】:
太棒了!您将Diff<T, U>
(T
和 U
作为可用于键的类型)声明为 3 种类型交集的 T
-keyed 子集:键入与 T
的值相同的键,键入never
表示 U
并使用 never
输入所有键。然后通过索引器传递它以获得正确的值类型。我说的对吗?
是的!但这确实有一个缺点。例如,Omit<a?: string, b?: boolean, "b">
生成 a: string | undefined
,它仍然接受 undefined
作为值,但丢失了 a
上的可选修饰符。 :(
@Qwertiy 它有效!非常感谢!我编辑了帖子。但我想知道有什么区别,因为据我所见,它们与Pick
的类型定义实际上是相同的。
请注意,对于 TS 3.5,标准库对 Omit
的定义与此处给出的不同。在 stdlib 中,是 type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
的变化,虽然很小,但 has caused some debate,所以要注意区别。
请注意,如果您尝试排除的属性不存在,这不会抱怨。例如,Omit<Test, "doesNotExist">
仍然有效。如果您不希望这样,您可以使用来自ts-essentials 的StrictOmit
。如果您想确保意外重命名属性不会违反省略规则,这将非常有用。【参考方案3】:
使用 typescript 2.8,您可以使用新的内置 Exclude
类型。 2.8 release notes 实际上在“预定义条件类型”一节中提到了这一点:
注意:Exclude 类型是 Diff 类型的正确实现 建议在这里。 [...] 我们没有包含 Omit 类型,因为 它被简单地写成
Pick<T, Exclude<keyof T, K>>
。
将此应用于您的示例,类型 XY 可以定义为:
type XY = Pick<XYZ, Exclude<keyof XYZ, "z">>
【讨论】:
【参考方案4】:如果您更喜欢使用库,请使用ts-essentials。
import Omit from "ts-essentials";
type ComplexObject =
simple: number;
nested:
a: string;
array: [ bar: number ];
;
;
type SimplifiedComplexObject = Omit<ComplexObject, "nested">;
// Result:
//
// simple: number
//
// if you want to Omit multiple properties just use union type:
type SimplifiedComplexObject = Omit<ComplexObject, "nested" | "simple">;
// Result:
// (empty type)
PS:你会在那里找到很多其他有用的东西;)
【讨论】:
【参考方案5】:打字稿 3.5
从 Typescript 3.5 开始,将包含 Omit 帮助器:TypeScript 3.5 RC - The Omit Helper Type
你可以直接使用,更新的时候应该去掉自己定义的Omit helper。
【讨论】:
【参考方案6】:在Typescript 3.5+:
interface TypographyProps
variant: string
fontSize: number
type TypographyPropsMinusVariant = Omit<TypographyProps, "variant">
【讨论】:
【参考方案7】:我喜欢这样:
interface XYZ
x: number;
y: number;
z: number;
const a:XYZ = x:1, y:2, z:3;
const x, y, ...last = a;
const z, ...firstTwo = a;
console.log(firstTwo, last);
【讨论】:
从中打印出什么? @frlzjosh 运行它并找出答案? 是的,我应该在这方面更新自己。我在一个在线打字稿编译器上运行它。这是一个很好的解决方案,虽然我发现 Omit 和 Picks 更具可读性【参考方案8】:省略
单一属性
type T1 = Omit<XYZ, "z"> // x: number; y: number;
多个属性
type T2 = Omit<XYZ, "y" | "z"> // x: number;
有条件的属性
例如所有字符串类型:type Keys_StringExcluded<T> =
[K in keyof T]: T[K] extends string ? never : K [keyof T]
type XYZ = x: number; y: string; z: number;
type T3a = Pick<XYZ, Keys_StringExcluded<XYZ>> // x: number; z: number;
具有 TS 4.1 key remapping / as
clause 的映射类型 (PR) 的较短版本:
type T3b = [K in keyof XYZ as XYZ[K] extends string ? never : K]: XYZ[K]
// x: number; z: number;
string
模式的属性
例如排除 getter(带有 'get' 字符串前缀的道具)
type OmitGet<T> = [K in keyof T as K extends `get$infer _` ? never : K]: T[K]
type XYZ2 = getA: number; b: string; getC: boolean;
type T4 = OmitGet<XYZ2> // b: string;
注意:TS 4.1 支持以上template literal types。
注2:这里可以also writeget$string
代替get$infer _
。
Pick
, Omit
and other utility types
How to Pick and rename certain keys using Typescript?(重命名而不是排除)
Playground
【讨论】:
你应该得到 Oscript以上是关于从类型中排除属性的主要内容,如果未能解决你的问题,请参考以下文章