Repository navigation
Add a new type Required #15012
Description
Activity
type Required<T> = T & { [P in keyof T]: T[P]; } let a: Required<{ x: number }> = { }; // Property 'x is missing in type '{}'
it seems to work well.
AA (@monolithed) That snippet doesn't have any optional properties in the type you're passing as a type argument to
Required. This corrected snippet doesn't have the expected error:type Required<T> = T & { [P in keyof T]: T[P]; } let a: Required<{ x?: number }> = { };
Reacted by Roaders and Andy PattersonAsad Saeeduddin (@masaeedu), oh, you're right (
aluanhaddad commented
on Apr 5, 2017 ContributorMore actionsThis is what you are looking for I believe. #13224
This is what you are looking for I believe. #13224
So, why the following operation
[P in keyof T]: T[P]is not working as expected?Reacted by Asad SaeeduddinAA (@monolithed)
The operation is a homomorphic mapping, which have been configured to preserve optional and readonly modifiers. To get the desired behavior, you would need to do:type RequiredInternal<T, K extends keyof T> = { [P in K]: T[P] }; // Use type parameter to force it not to be considered homomorphic type Required<T> = T & RequiredInternal<T, keyof T>; let a: Required<{ x?: number }> = { }; // => Property 'x' is missing in type '{}'
Reacted by Meirion HughesPyroVortex No, I tried that yesterday (I think it might have been your comment on another issue). With
tscversion2.2.1, and the following files:// tsconfig.json { "compilerOptions": { "module": "commonjs", "target": "es5", "strictNullChecks": true, "noImplicitAny": false, "sourceMap": false } }
// main.ts type RequiredInternal<T, K extends keyof T> = { [P in K]: T[P] }; // Use type parameter to force it not to be considered homomorphic type Required<T> = T & RequiredInternal<T, keyof T>; let a: Required<{ x?: number }> = { }; // No error here let x: number = a.x; // Error here because number | undefined is not assignable to number
The expected error does not appear, and
ais typed as having a potentially undefinedxproperty (number | undefined).Reacted by Roaders and Jørgen TvedtAsad Saeeduddin (@masaeedu)
Huh. In the current version in the TypeScript Playground with strictNullChecks enabled, I get an error for the first assignment (missing property), but I do still see the error you are mentioning for the second.In general, we lack an ability to remove a type from a union using pure type manipulation (we can do it with an actual value).
PyroVortex How did you enable
strictNullChecksin playground?aluanhaddad commented
on Apr 6, 2017 ContributorMore actionsPyroVortex Asad Saeeduddin (@masaeedu) I am too trying to create type that maps optional fields to required fields. I get the example above to raise an error with TS 2.1.4 and in the playground (which it seems to be using). From 2.1.5 and up it does not give me an error anymore. Any idea why it is so?
Reacted by jmlee2k, Mike Hill and Sam Beran- addedNeeds InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.
on May 24, 2017 This feature is very handy in react stateful components when you want to specify the default state, and you want to make sure you don't miss any state.
Reacted by SamI'm still running into issues with this in TS 2.4.1. I've tried breaking the homomorphic relationship, as described in #13723, and I believe this does that because the fields are now required, but instead of removing all traces of optional parameters it keeps the type union with
undefined. Is this intentional?type RequiredInternal<T extends {[key: string]: any}, K extends string> = { [P in K]: T[P]}; type Required<T> = RequiredInternal<T, keyof T>; // As expected: No compile error const val1: Required<{x?: number}> = {x: 1}; // As expected: Compile error: // TS2322: Type '{}' is not assignable to type 'RequiredInternal<{ x?: number | undefined; }, "x">'. Property 'x' is missing in type '{}'. const val2: Required<{x?: number}> = {}; // Not expected?: No compile error // Expected something like TS2322: Type '{ x: undefined; }' is not assignable to type 'RequiredInternal<{ x?: number | undefined; }, "x">'. Types of property 'x' are incompatible. Type 'undefined' is not assignable to type 'number'. const val3: Required<{x?: number}> = {x: undefined};
14 remaining items
The workaround Samuel Sonne (@ssonne) has doesn't work in all contexts, unfortunately, too. For example, if you enable
strictNullChecks:interface Optional { foo?: () => {} } type Strict = Required<Optional> const impl: Strict = { foo() {} }; impl.foo(); // ^ Object is possibly 'undefined'.
We can make required properties, but they still have nullable values. The last piece is NonNullable type.
type Required<T> = { [P in Purify<keyof T>]: NonNullable<T[P]>; }; type Purify<T extends string> = { [P in T]: T; }[T]; type NonNullable<T> = T - undefined - null;
Well, right now we can have some workaround that allows you to define required type from partial one
type PartialPerson = { name? : number; surname? : string; } declare function makeRequired<T>(notRequired : Partial<T>): T; let __requiredPersonVariable = null as any && makeRequired({} as PartialPerson); type RequiredPerson = typeof __requiredPersonVariable;
Then if we got #6606 we could do something like this (I guess, I'm not sure how it would work with generic type aliases if it was implemented):
type Required<T> = typeof( null as any && makeRequired({} as T))
For me It's another example how useful #6606 would be if we had it :)
Reacted by ZpdDG4gtaI've found out that
T & {}simplifies to non-nullable type, i.e.:type Required<T> = { [P in Purify<keyof T>]: NonNullable<T[P]>; }; type Purify<T extends string> = { [P in T]: T; }[T]; type NonNullable<T> = T & {};
Thanks to falsandtru (@falsandtru) for the Purify method.
See: Playground (remember to enable strictNullChecks).
Reacted by NNReacted by Tom Crockett, Aluan Haddad, Ian MacLeod, SlurpTheo, Kirill Agalakov, Meirion Hughes, Samuel Sonne, David Fahlander, fsubal, Alvis Tang and 4 moreGreat! Wesley Wigham (@weswigham) Nathan Shively-Sanders (@sandersn) Anders Hejlsberg (@ahejlsberg) Can we use
type NonNullable<T> = T & {};as a stable API?Very nice Bazyli Brzóska (@niieani)! And it makes sense:
{}contains all values exceptundefinedandnull, so intersecting with it excludes those and nothing else.Reacted by Aluan Haddad and Samuel SonneFor those interested, I've added
Required(andNonNullable) to Type Zoo.Reacted by Mariusz Pawelski, Samuel Sonne, David Fahlander and Jørgen TvedtNow the latest version is:
type Required<T> = T extends object ? { [P in Purify<keyof T>]: NonNullable<T[P]>; } : T; type DeepRequired<T, U extends object | undefined = undefined> = T extends object ? { [P in Purify<keyof T>]: NonNullable<T[P]> extends NonNullable<U | Function | Class> ? NonNullable<T[P]> : DeepRequired<NonNullable<T[P]>, U>; } : T;
This type can stop the processing with the specified object types like
DeepRequired<obj, Element>.https://github.com/falsandtru/spica/blob/master/src/lib/type.ts
https://github.com/falsandtru/spica/blob/master/src/lib/type.test.tsReacted by AA and Bazyli Brzóska- addedFixedA PR has been merged for this issueA PR has been merged for this issueand removedNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.
on Feb 13, 2018 falsandtru (@falsandtru) And as of today there's no need for
Purify:type Required<T> = T extends object ? { [P in keyof T]-?: NonNullable<T[P]>; } : T; type DeepRequired<T, U extends object | undefined = undefined> = T extends object ? { [P in keyof T]-?: NonNullable<T[P]> extends NonNullable<U | Function | Class> ? NonNullable<T[P]> : DeepRequired<NonNullable<T[P]>, U>; } : T;
this should also handle assignability while things are still generic better, too; or at least that's the goal.
Reacted by Aluan Haddad, Mikael Lirbank and Dmitrii KanatnikovReacted by Aluan Haddad and tipngRight, I'll try to use the new syntax later.
- locked and limited conversation to collaborators
on Jul 3, 2018

It would be nice to have a new type that allows property to be required as opposited to
Partial: