-
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
Mapped types behave strangely on primitive types #13351
Comments
See #12447. It generally isn't meaningful to apply mapped types to primitives, but in recursive types such as your example it is going to happen since types are rarely "objects all the way down". Ideally we'd have something like conditional types (#12424) that would allow you to provide alternative behavior for primitive types. |
Thanks. Conditionals would be great (e.g. test if T[K] is readonly to decide whether a corresponding property should also be readonly). But re: "Furthermore, when a primitive type is substituted for T in an isomorphic mapped type, we simply produce that primitive type." My question is, what use case does that fit? I'm finding that "no properties" would be better mapped to "no properties." |
I think |
Hmm, maybe I'm misinterpreting this feature! :) I thought in this context an interface becomes a compile-time "dictionary of string to type", for use in meta-programming. The special case for primitive By including the input type in the output it seems like levels are getting mixed. I'm generating an output type (with a structure I specify), derived from information about an input type, so the raw input information has no business appearing directly in the output. I experimented with adding a second type parameter: type Meta<T, A> = {
readonly[P in keyof T]: {
value: T[P];
also: A;
readonly children: Meta<T[P], A>;
};
}
interface Input {
x: string;
y: number;
}
declare const output: Meta<Input, boolean>;
const shouldFail: { important: boolean } = output.x.children; Now the type of |
No, it turns out we have a bug related to instantiation of mapped types in contexts with type parameters other than the one being mapped. Your example should be an error (and will be once we fix the bug). |
Given:
I'd expect
children
to either be the empty type{}
(ifT
has no properties) or to only have properties of the shape{ value: T, children: { ... } }
.But instead, for
Meta<boolean>
,children
is apparentlyboolean
, like the definition ofMeta
is simply ignored and replaced with its type argument. Same substitution occurs fornumber
,string
,null
,undefined
andnever
. What's the reasoning behind this? It seems inconsistent.The text was updated successfully, but these errors were encountered: