Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining the inverse of Partial<T> in TypeScript

Tags:

typescript

TypeScript has a Partial type defined by default, so that you can say Partial<{x: number, y: string}> to get a type like {x?: number, y?: string} (the type's properties become optional). It is defined as

type Partial<T> = {
    [P in keyof T]?: T[P]
}

I am trying to define the inverse, let's call it Full<T>, which makes sure all properties in the object are required. I started with the obvious definition:

type Full<T> = {
    [P in keyof T]: T[P]
}

Which is just Partial with the question mark removed. Unfortunately, this doesn't work—optional properties remain optional. It seems typescript somehow, in some circumstances, preserves information about the requiredness of the property names in the keyof type.

Interestingly, if you store that type in an intermediate type name, that information is dropped. I.e. this works:

type Config = {foo: number, bar?: string}
type ConfigKey = keyof Config
type FullConfig = {[K in ConfigKey]: Config[K]}

In FullConfig (at least with TypeScript 3.3), bar is required. But if you inline keyof Config into the definition of FullConfig, it is optional again.

I'd like this to be a single, easy-to-use type, and since I'm not aware of a way for a type declaration to define local types, this hack doesn't seem to help much there.

Is there any trick I'm missing?

like image 228
Marijn Avatar asked Mar 04 '19 12:03

Marijn


1 Answers

Mapped types are not all created equal. Homomorphic mapped types preserve modifiers of the mapped type. From the pull request introducing this feature:

With this PR we preserve property modifiers in homomorphic (structure preserving) mapped types. A mapped type of the form { [P in keyof T]: X } is homomorphic with T (because it has the same set of properties as T) and now preserves the optional and readonly modifiers as they exist on the properties in T.

Starting from 2.8 you can remove modifiers from such types using a - (see PR) :

type Full<T> = {
  [P in keyof T]-?: T[P];
}

Note

You can use the predefined Required type from the standard library which does the exact same thing as Full.

like image 160
Titian Cernicova-Dragomir Avatar answered Nov 14 '22 21:11

Titian Cernicova-Dragomir