TypeScriptの新しい条件型(または別の手法)を使用して、修飾子に基づいてインターフェイスから特定のプロパティのみを選択する方法はありますか?たとえば、...
interface I1 {
readonly n: number
s: string
}
前のタイプに基づいて、次のような新しいタイプを作成したいと思います。
interface I2 {
s: string
}
更新2018-10: @ MattMcCutchen は、isreadonly
フィールドを検出できる(以下の削除されたパッセージを無効にする)ことが可能であると判断しました。 この回答 に示されています。これを構築する方法は次のとおりです。
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
プロパティを適切にチェックしません なので、いつでも{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}
を拡張しないということです。タイプからオプションのプロパティを削除する方法を作成する方法は次のとおりです。
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
に存在しないため、excludedになる可能性があります。
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} ????
ただし、extractprivate
またはprotected
プロパティは、除外するのが非常に簡単であるのと同じ理由で、不可能な場合があります。keyof Foo
にはありません。そして、abstract
を含むこれらすべてについて、型エイリアスのプロパティにそれらを追加することはできません(これらはクラスのみの修飾子です)ので、それらに触れるために私が考えることはあまりありません。
さて、それが役立つことを願っています。