Update 2018-10: @MattMcCutchen has figured out that it is possible to detect readonly fields (invalidating the struck-out passage below), as shown in this answer. Here is a way to build it:
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];
If you want to extract the writable fields from an interface, you can use the above WritableKeys definition and Pick together:
interface I1 {
readonly n: number
s: string
}
type I2 = Pick<I1, WritableKeys<I1>>;
// equivalent to { s: string; }
Hooray!
For `readonly`, I don't think you can extract those. I've [looked at this issue before](https://github.com/Microsoft/TypeScript/issues/13257#issuecomment-308528175) and it wasn't possible then; and I don't think anything has changed.
Since the compiler doesn't soundly check readonly properties, you can always assign a {readonly n: number} to a {n: number} and vice-versa. And therefore the obvious TSv2.8 conditional type check doesn't work. If, for example, {n: number} were not considered assignable to {readonly n: number} then you could do something like:
// 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 {}
But you can't. There's some interesting discussion about this in a GitHub issue originally named "readonly modifiers are a joke".
Sorry! Good luck.
For optional properties, you can indeed detect them and therefore extract or exclude them. The insight here is that {} extends {a?: string}, but {} does not extend {a: string} or even {a: string | undefined}. Here's how you could build a way to remove optional properties from a type:
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}
So that's good.
Finally, I don't know if you want to be able to do stuff with the class-only property modifiers like public, private, protected, and abstract, but I would doubt it. It happens that the private and protected class properties can be excluded pretty easily, since they are not present in 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}
But extracting the private or protected properties might be impossible, for the same reason that excluding them is so easy: keyof Foo doesn't have them. And for all of these including abstract, you can't add them to properties in type aliases (they are class-only modifiers), so there's not much I can think of to do to touch them.