TypeScrip条件类型-筛选出只读属性/仅选择必需属性 [英] TypeScript conditional types - filter out readonly properties / pick only required properties

查看:4
本文介绍了TypeScrip条件类型-筛选出只读属性/仅选择必需属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在TypeScrip(或者可能是其他技术)中使用新的条件类型,有没有一种方法可以根据它们的修饰符从接口中只挑选某些属性?例如,拥有...

interface I1 {
    readonly n: number
    s: string
}

我想在前一个类型的基础上创建一个新类型,如下所示:

interface I2 {
    s: string
}

推荐答案

更新2018-10:@MattMcCutchen发现可以检测readonly字段(使下面删除的段落无效),如this answer所示。以下是构建它的方法:

type IfEquals<X, Y, A=X, B=never> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? A : B;

type WritableKeys<T> = {
  [P in keyof T]-?: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, P>
}[keyof T];

type ReadonlyKeys<T> = {
  [P in keyof T]-?: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, never, P>
}[keyof T];

如果要从接口提取可写字段,可以同时使用上述WritableKeys定义和Pick

interface I1 {
    readonly n: number
    s: string
}

type I2 = Pick<I1, WritableKeys<I1>>; 
// equivalent to { s: string; }

万岁!

<罢工> 对于readonly,我认为您无法提取它们。我已经looked at this issue before,这在当时是不可能的;我认为一切都没有改变。

由于the compiler doesn't soundly check readonly properties,您始终可以将{readonly n: number}分配给{n: number},反之亦然。因此,明显的TSv2.8条件类型检查不起作用。例如,如果{n: number}不被认为可分配给{readonly n: number},则可以执行如下操作:

// does not work, do not try this
type ExcludeReadonlyProps<T> = Pick<T,
  { [K in keyof T]-?:
    ({ readonly [P in K]: T[K] } extends { [P in K]: T[K] } ? never : K)
  }[keyof T]>

type I2 = ExcludeReadonlyProps<I1> // should be {s: string} but is {} 🙁

但你不能。在GitHub issue originally named "readonly modifiers are a joke"中有一些关于这方面的有趣的讨论。

对不起!祝好运。


对于可选属性,您确实可以检测到它们,从而提取或排除它们。这里的洞察是{}扩展{a?: string},但{}不扩展{a: string},甚至{a: string | undefined}。下面是如何构建一种从类型中删除可选属性的方法:

type RequiredKeys<T> = { [K in keyof T]-?:
  ({} extends { [P in K]: T[K] } ? never : K)
}[keyof T]

type OptionalKeys<T> = { [K in keyof T]-?:
  ({} extends { [P in K]: T[K] } ? K : never)
}[keyof T]

type ExcludeOptionalProps<T> = Pick<T, RequiredKeys<T>>

type I3 = { 
  a: string, 
  b?: number, 
  c: boolean | undefined
}

type I4 = ExcludeOptionalProps<I3>;
// {a: string; c: boolean | undefined} 🙂

所以这很好。


最后,我不知道您是否希望使用publicprivateprotectedabstract等仅限类的属性修饰符,但我对此表示怀疑。碰巧privateprotected类属性很容易被排除,因为它们不存在于keyof

class Foo {
  public a = ""
  protected b = 2
  private c = false
}
type PublicOnly<T> = Pick<T, keyof T>; // seems like a no-op but it works
type PublicFoo = PublicOnly<Foo>; // {a: string} 🙂

提取privateprotected属性可能是不可能的,原因与排除它们是如此容易:keyof Foo没有它们。对于包括abstract在内的所有这些元素,您不能将它们添加到类型别名中的属性中(它们是仅限类的修饰符),因此我想不出什么办法来触及它们。


好的,希望这会有帮助。

这篇关于TypeScrip条件类型-筛选出只读属性/仅选择必需属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆