Skip to content
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

Can't remove optional modifier from properties on tree #24250

Closed
massimonewsuk opened this issue May 18, 2018 · 2 comments
Closed

Can't remove optional modifier from properties on tree #24250

massimonewsuk opened this issue May 18, 2018 · 2 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@massimonewsuk
Copy link

massimonewsuk commented May 18, 2018

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 remain

Expected 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.

@massimonewsuk
Copy link
Author

massimonewsuk commented 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:

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

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 Entity as T & { 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

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label May 21, 2018
@massimonewsuk
Copy link
Author

I am closing this issue in favour of #24318

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

2 participants