[英]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} 🙂
所以這很好。
最后,我不知道您是否希望能夠使用諸如public
、 private
、 protected
和abstract
之類的僅限類的屬性修飾符來做一些事情,但我對此表示懷疑。 碰巧可以很容易地排除private
和protected
類屬性,因為它們不存在於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} 🙂
但是提取private
或protected
屬性可能是不可能的,因為排除它們很容易: keyof Foo
沒有它們。 對於包括abstract
在內的所有這些,您不能將它們添加到類型別名中的屬性(它們是僅限類的修飾符),因此我想不出太多可以觸及它們的方法。
好的,希望有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.