Skip to content

Required<T> optional properties type validation will not work #29991

Description

@misuken-now

TypeScript Version: 3.2.0-rc <= 3.4.0-dev.20190220

Search Terms: Required

Code

const a: Required<{ a?: 1; x: 1 }> = { a: 1, x: 1 };
const b: Required<{ b?: 1; x: 1 }> = { b: 1, x: 1 };
export let A = a;
export let B = b;
A = b; // No Error
B = a; // No Error

a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'.
b.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'.

Expected behavior:

Error:(5, 1) TS2322: Type 'Required<{ b?: 1 | undefined; x: 1; }>' is not assignable to type 'Required<{ a?: 1 | undefined; x: 1; }>'.
  Property 'a' is missing in type 'Required<{ b?: 1 | undefined; x: 1; }>'.
Error:(6, 1) TS2322: Type 'Required<{ a?: 1 | undefined; x: 1; }>' is not assignable to type 'Required<{ b?: 1 | undefined; x: 1; }>'.
  Property 'b' is missing in type 'Required<{ a?: 1 | undefined; x: 1; }>'.

When it is "3.1.6" it will be like that.

Actual behavior:

No Error

Playground Link:

link

Related Issues:

Activity

  1. jack-williams commented on Feb 20, 2019

    @jack-williams
    Collaborator

    This looks to be related to variance markers used for generic mapped types---a very similar problem to #29698. When relating a and b, I believe it is just relating the type arguments in a covariant way, which holds for assigning { a?: 1; x: 1 } to and from { b?: 1; x: 1 }. The variance markers do not reflect how the keys of the type arguments are used.

    You can see behaviour by replacing Required with a structurally equivalent, but different alias. Variance markers are not used in this instance, and type checking falls back to structural checking. The error correctly gets flagged in this case.

    type Required2<T> = { [P in keyof T]-?: T[P]; };
    const a: Required<{ a?: 1; x: 1 }> = { a: 1, x: 1 };
    const b: Required2<{ b?: 1; x: 1 }> = { b: 1, x: 1 };
    export let A = a;
    export let B = b;
    A = b; //  Error!
    B = a; //  Error!

    I've been wrong on this before though. You'll most likely need Anders Hejlsberg (@ahejlsberg) or Wesley Wigham (@weswigham) to give a definitive answer.

  2. misuken-now commented on Feb 21, 2019

    @misuken-now
    Author

    Thanks for looking into this Jack Williams (@jack-williams).

    It was a difficult problem to understand for me.
    I was saved because it provided information.

    Once it is written as follows, it will be as intended, so it seems to be temporarily resolved.

    type Required2<T> = Required<{ [P in keyof T]-?: T[P]; }>;
    
    const a: Required2<{ a?: 1; x: 1 }> = { a: 1, x: 1 };
    const b: Required2<{ b?: 1; x: 1 }> = { b: 1, x: 1 };
    export let A = a;
    export let B = b;
    A = b; // Property 'a' is missing in type 'Required<{ b: 1; x: 1; }>' but required in type 'Required<{ a: 1; x: 1; }>'.
    B = a; // Property 'b' is missing in type 'Required<{ a: 1; x: 1; }>' but required in type 'Required<{ b: 1; x: 1; }>'.
    
    a.b; // Property 'b' does not exist on type 'Required<{ a?: 1; x: 1; }>'.
    b.a; // Property 'a' does not exist on type 'Required<{ b?: 1; x: 1; }>'.
  3. weswigham commented on Mar 6, 2019

    @weswigham
    Member

    This is fixed in master.

  4. jack-williams commented on Mar 6, 2019

    @jack-williams
    Collaborator

    Wesley Wigham (@weswigham) I can't seem to reproduce: 5bd73f5. It should error on the first two assignments, right?

    (P.S. excuse my spelling)

  5. weswigham commented on Mar 6, 2019

    @weswigham
    Member

    Your baselines are right - getting an error on those two accesses is intended, since the Required type is meant to strip them out, and the assignments should all be allowed, since they both evaluate to {x: number}.

  6. jack-williams commented on Mar 6, 2019

    @jack-williams
    Collaborator

    Is Required not meant to remove ? modifiers, rather than strip out optional properties?

  7. weswigham commented on Mar 7, 2019

    @weswigham
    Member

    Ah, derp, you're right - I was confusing it with a RequiredKeys function I'd been looking at.hmmm yeah, those assignments shouldn't work. Hmm.

  8. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScript

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions