Skip to content

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

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

Closed
misuken-now opened this issue Feb 20, 2019 · 7 comments · Fixed by #30416
Closed

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

misuken-now opened this issue Feb 20, 2019 · 7 comments · Fixed by #30416
Assignees
Labels
Bug A bug in TypeScript

Comments

@misuken-now
Copy link

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:

@jack-williams
Copy link
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 @ahejlsberg or @weswigham to give a definitive answer.

@misuken-now
Copy link
Author

Thanks for looking into this @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; }>'.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Feb 27, 2019
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 3.5.0 milestone Feb 27, 2019
@weswigham
Copy link
Member

This is fixed in master.

@jack-williams
Copy link
Collaborator

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

(P.S. excuse my spelling)

@weswigham
Copy link
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}.

@jack-williams
Copy link
Collaborator

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

@weswigham
Copy link
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
4 participants