Repository navigation
Can't remove optional modifier from properties on tree #24250
Description
TypeScript Version: 2.9.1-insiders.20180516
Search Terms:
mapped types
conditional mapped types
conditional required types
filter mapped types
Code
// Utility types
type Entity<T> = T;
type Eager<T> = {
[P in keyof T]-?: T[P] extends Entity<infer U> ? Eager<U> : never;
} & {
[P in keyof T]: T[P] extends Entity<infer U> ? never : T[P];
}
// Database models
type Person = {
firstName: string;
lastName: string;
addresses?: Entity<Address[]>;
}
type Address = {
line1: string;
town: string;
telephoneLine: Entity<TelephoneLine>;
}
type TelephoneLine = {
phoneNumber: string;
features?: {
hasBroadband: boolean;
}
}
declare var person: Person;
person.addresses[0] // EXPECTED - addresses is possibly undefined
declare var eagerLoadedPerson: Eager<Person>
eagerLoadedPerson.addresses[0].line1; // should work fine but doesn't
eagerLoadedPerson.addresses[0].telephoneLine.phoneNumber; // should work fine but doesn't
eagerLoadedPerson.addresses[0].telephoneLine.features.hasBroadband // EXPECTED - should give error because "features" is not an entity so the ? modifier should remainExpected behavior:
I would expect the above code example to work (except for the EXPECTED errors as described). Well, not exactly the above code example, I appreciate the Eager type is a bit messed up.
Actual behavior:
Doesn't work - I can't seem to get a utility type Eager that will make all marked optional properties mandatory. In fact, forget marked properties. I can't even write an Eager type that will remove the optional modifier from all properties in the tree. For example the following example doesn't work either:
// Utility types
type Entity<T> = T;
type primitive = string | number | boolean | null | undefined;
type Eager<T> = NonNullable<{
[P in keyof T]: T[P] extends primitive ? T[P] : Eager<T[P]>;
}>Related issues
#23199 - I think this one is related but the filtering is finally achieved by using the property type - I can't seem to do that.
What I'm trying to achieve
We are using the sequelize ORM and we define some relationships on our models. When we query for our model, if we don't fetch the relationship then it will come back undefined. So we want our base type to represent that. However, sometimes we query for the whole tree so we'd like a utility type that will mark all those relation properties as being present.
Activity
massimonewsuk commentedon May 18, 2018
I think I found a PR which fixes the scenario where you can't make the whole tree mandatory: #23592
The following code works in 2.9.1 but not in 2.8.3:
But now I need a way to say only certain properties should be eager, and that others might still not be there (i.e. TelephoneLine.features is not an entity, it genuinely might not be there). I was planning to use marker types for this but it seems that won't work because of the nature of structural types. I tried defining
EntityasT & { some kind of property or symbol tag }and if the property or symbol tag is optional (i.e.property?) then everything matches, and if it is mandatory then nothing matches.I think that comes down to this maybe? #202
massimonewsuk commentedon May 22, 2018
I am closing this issue in favour of #24318