-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Keysof type operator #10425
Keysof type operator #10425
Conversation
01b0744
to
b156f71
Compare
Also probably solves #7722. How would classes and namespaces work with this? ( if they should in the first place 😅 ) and how about index signatures? interface A {
foo: string;
[property: string]: any;
} what will be |
@alitaheri: |
if (!type.resolvedBaseUnion) { | ||
// Skip any essymbol members and remember to unescape the identifier before making a type from it | ||
const memberTypes = map(filter(getPropertiesOfType(type.baseType), | ||
symbol => !startsWith(symbol.name, "__@")), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you split this into intermediate variables?
When this going to landed? |
@whitecolor We need to discuss this at a design meeting. There are small details that can make all the difference (such as what to do with index signatures). |
@DanielRosenwasser it would be cool if another part for #1295 would be implemented soon |
I think this is a big step forward for the type system. The question I have, and sorry if this has already been answered, is this: What is the enumeration algorithm used?
On the one hand, it could be very surprising to not get the property keys of super class properties, especially as subclassing becomes more and more fashionable. On the other, it would be equally surprising if it behaved differently from Personally, I would prefer it to only return enumerable own properties, but I almost never create class hierarchies in TypeScript. |
@aluanhaddad Problem is that enumerable own properties aren't encoded in the type system and there's not really a straightforward way we've thought of to add it. @sandersn ran into similar issues with the object rest & spread operators. |
@DanielRosenwasser thank you for clarifying. It makes a lot of sense that the language does not track own properties because statically modelling the flexibility of JavaScript's composition mechanisms would seem to preclude doing so. Perhaps if this operator walks the prototype chain a different name would be appropriate.
|
I created #11813 because I was not aware of this. I have closed it but it can still be used as a real world use case for the need of this operator. |
@aluanhaddad I can understand why you expect That said, I'd find it unfortunate if this very useful operator was restricted to enumerable-own properties. Here's an example scenario I ran into today that got me thinking about this feature again: creating a hard-fail version of the index-for-friendly-access trick: class X {
constructor(private name: string) {}
}
let x = new X("Godfrey");
x['name'] // type checks, "Godfrey", type is string, as expected
x['nmae'] // type checks, undefined, type is any, unexpected In other words, this trick conflates the elimination of privacy checks with a willingness to accept successful type-checking and We could use the class X {
constructor(private name: string) {}
}
let x = new X("Godfrey");
x['name'] // type checks, value is "Godfrey", type is string, as expected
x['nmae'] // type checks, value is undefined, type is any, unexpected
function get<T, K extends keysof T>(obj: T, key: K) {
return obj[key];
}
let x = new X("Godfrey");
get(x, 'name') // type checks, "Godfrey", type is string (?), as expected
get(x, 'nmae') // fails to type check Whether this works or not depends on whether Regardless of those details, this illustrates that there may be valid use-cases for My own perspective is that This might also argue for a few flavors of Finally, I also wonder whether not encoding enumerable/own in the type system will be practical in the long-term, especially considering the soon-to-be-included object-spread ( |
@wycats I think you're points about overall usefulness outweigh my arguments about consistency with existing features. While I don't use classes particularly often I do find the object-spread example very compelling. In light of that feature, requiring ownness would kill a lot of the usefulness even in scenarios involving simple object literals. Also if manifest mixin support is ever added to ECMAScript, restricting it to enumerable own properties would also be very unfortunate. I am convinced. |
Closing as this has been superseded by #11929. |
Fixes half of #1295. (Honestly, that issue is like proposals for three separate but interoperating features) The remaining parts of #1295 are what I call a "type access expression" - a mirror of element access expressions, but for types (quite literally the same logic) - and altering index resolution logic to, rather than using unions to check for index signature compatibility, be able to use a union of string literals to create a union of the types of those members.
The part that this PR addresses is an operator for finding all of the keys of an arbitrary type. This PR adds a new "type operator" (akin to
typeof
) -keysof
. Used like so:A parameter or return type being a
keysof
type causes it to be contextually types as a string literal if need be. Akeysof
type resolves to a union of the string literal types of the keys of the given type when it is actually resolved (which it is resolved to for relationship checking). It isStringLike
, and as such it has the apparent type of a string. It is effectively sugar for writing out the union type of all the keys of an object by hand, except it is also able to be generically instantiated.cc @DanielRosenwasser