Skip to content

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

Closed
@massimonewsuk

Description

@massimonewsuk

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions