Skip to content
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 type optional -> required property issue #13224

Closed
JakeGinnivan opened this issue Dec 30, 2016 · 4 comments
Closed

Mapped type optional -> required property issue #13224

JakeGinnivan opened this issue Dec 30, 2016 · 4 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@JakeGinnivan
Copy link

TypeScript Version: 2.1.4

Code
https://github.com/JakeGinnivan/TypeScriptMappedTypeIssue

Expected behavior:
The mapped type

export type PropDescriptions<T> = {
    [P in keyof T]: string
}

Is marking all the properties as required, I would expect this to fail:

interface ThingProps {
    prop1: string
    prop2?: string
}

const expected: PropDescriptions<ThingProps> = {
    prop1: 'Ok'
}

with Property 'prop2' is missing in type {...}

Actual behavior:
No compilation error

@JakeGinnivan
Copy link
Author

As a side note, it would be awesome if you could iterate at runtime on the keys of an interface. I guess that starts moving into the reflection questions, but it would be super handy if code could be emitted based on type information. So not runtime reflection but static templating.

I probably need to generate the styleguide from the typescript source rather than the approach I am taking.

@mhegazy
Copy link
Contributor

mhegazy commented Dec 30, 2016

Mapped types that are a homomorphic transformation are treated specially in the type system. the above type PropDescriptions is one of such. The type system knows that PropDescriptions<T> is a transformation of T, and it copies the readonly and ? modifiers on the new type as it is generated from the source. Think of ReadOnly<T>, where T has optional properties, you would expect the result to have optional properties as well.

You however change the mapping to make it a non-homomorphic transformation as such:

type PropDescriptions<T, K extends string> = {
  [P in K]: string
}

and you would instantiate it with:

const expected: PropDescriptions<ThingProps, keyof ThingProps> = ...

Notice the constraint on K is string; this way the type system can not assert that the result of this transformation is a homomorphic mapping on T, and thus no modifiers are copied through.

It is worth noting that if the constraint was K extends keyof T (e.g. the definition of type Pick in lib.d.ts`), the transformation would still be considered a homomorphic one.

@mhegazy mhegazy added the Working as Intended The behavior described is the intended behavior; this is not a bug label Dec 30, 2016
JakeGinnivan added a commit to JakeGinnivan/TypeScript-Handbook that referenced this issue Dec 31, 2016
@JakeGinnivan
Copy link
Author

Thanks, have opened a PR in the docs which adds some of this information. Appreciate the good explanation.

@JakeGinnivan
Copy link
Author

It would also be good to extend the docs to explain how to use the Pick and Record types.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

2 participants