从类型中排除属性

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&lt;T, U&gt;TU 作为可用于键的类型)声明为 3 种类型交集的 T-keyed 子集:键入与 T 的值相同的键,键入never 表示 U 并使用 never 输入所有键。然后通过索引器传递它以获得正确的值类型。我说的对吗? 是的!但这确实有一个缺点。例如,Omit&lt;a?: string, b?: boolean, "b"&gt; 生成 a: string | undefined,它仍然接受 undefined 作为值,但丢失了 a 上的可选修饰符。 :( @Qwertiy 它有效!非常感谢!我编辑了帖子。但我想知道有什么区别,因为据我所见,它们与Pick 的类型定义实际上是相同的。 请注意,对于 TS 3.5,标准库对 Omit 的定义与此处给出的不同。在 stdlib 中,是 type Omit&lt;T, K extends keyof any&gt; = Pick&lt;T, Exclude&lt;keyof T, K&gt;&gt;; 的变化,虽然很小,但 has caused some debate,所以要注意区别。 请注意,如果您尝试排除的属性不存在,这不会抱怨。例如,Omit&lt;Test, "doesNotExist"&gt; 仍然有效。如果您不希望这样,您可以使用来自ts-essentials 的StrictOmit。如果您想确保意外重命名属性不会违反省略规则,这将非常有用。【参考方案3】:

使用 typescript 2.8,您可以使用新的内置 Exclude 类型。 2.8 release notes 实际上在“预定义条件类型”一节中提到了这一点:

注意:Exclude 类型是 Diff 类型的正确实现 建议在这里。 [...] 我们没有包含 Omit 类型,因为 它被简单地写成Pick&lt;T, Exclude&lt;keyof T, K&gt;&gt;

将此应用于您的示例,类型 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

以上是关于从类型中排除属性的主要内容,如果未能解决你的问题,请参考以下文章

是从体型(RAML)中排除属性的方法吗?

递归排除 Typescript 中的只读属性

从帖子架构WP REST API中排除acf属性

如何从 Swift Codable 中排除属性?

从获取中排除属性/字段 - 核心数据

从覆盖报告中排除抽象属性