Closed
Description
Consider this interface:
interface A {
foo: string;
bar: Function;
}
With an operator such as membersof
we can have this type:
type MembersofA = membersof A; // equivalent of type MembersofA = 'foo' | 'bar';
Some caveats:
- Deceleration merging: I think the compiler is smart enough to resolve all merged properties before building the type for
membersof
. - Inheritance: If the compiler is smart enough to handle 1, this is a piece of cake 😄
- Index signatures: In case we have an interface like this:
interface A {
foo: string;
[property: string]: any;
}
The type should turn into: 'foo' | string
. Although I'm not so sure about this.
4. new
and function signature: I think these can be ignored safely:
interface A {
new ();
(bar: number): void;
foo: string;
}
type MembersofA = membersof A; // 'foo'
- Other type constructs:
- class: public members?
- enum: members, should be easy. maybe even easy for constant enums
- namespace: treated like interfaces
- type alias, union/intersection: doesn't make sense, does it?
There are many use cases. immutable js is the best one:
import {Map} from 'immutable';
interface MapShape {
foo: number;
bar: string;
baz: boolean;
}
const map = new Map<MapShape>();
map.set('blah', 1); // error, unless [other: string]: any; is added to MapShape
Accompanied by #6080 we can have type safety too:
map.set('bar', 1); // error: 1 is not string
Map would look like this:
class Map<T> {
set(prop: membersof T, value: any): Map<T>;
}
// or with "Value of string literal type as property names" (#6080)
class Map<T> {
set<U extends membersof T>(prop: U, value: T[U]): Map<T>;
}
// Although this might need to have the output of membersof T to be extensible!
This is easier to implementation than #1295.