簡體   English   中英

TypeScript 條件類型 - 過濾掉只讀屬性/只選擇需要的屬性

[英]TypeScript conditional types - filter out readonly properties / pick only required properties

在 TypeScript 中使用新的條件類型(或者可能是另一種技術),有沒有辦法根據它們的修飾符從接口中只選擇某些屬性? 例如,擁有...

interface I1 {
    readonly n: number
    s: string
}

我想基於前一個類型創建一個新類型,如下所示:

interface I2 {
    s: string
}

更新2018-10: @MattMcCutchen已經想通了,它可以檢測readonly域(以下無效被撞擊出通道),如圖這個答案 這是一種構建方法:

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 ,我認為您無法提取這些內容。 我以前 看過這個問題,當時是不可能的; 我認為沒有任何改變。

由於 編譯器沒有徹底檢查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 {} 🙁
 
 

但你不能。 最初名為“ readonly修飾符是個笑話”GitHub 問題中有一些關於此的有趣討論。

對不起! 祝你好運。


對於可選屬性,您確實可以檢測它們並因此提取或排除它們。 這里的見解是{}擴展{a?: string} ,但{}不擴展{a: string}甚至{a: string | undefined} {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在內的所有這些,您不能將它們添加到類型別名中的屬性(它們是僅限類的修飾符),因此我想不出太多可以觸及它們的方法。


好的,希望有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM