-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Recursive mapped type inference not working as expected #24318
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
Comments
Here are some examples where it works as expected // Normal nested stuff
type Node = {
always: {
property: string;
}
maybe?: {
property: string;
}
leaf?: Node;
};
type EverythingPresent<T> = { [P in keyof T]-?: EverythingPresent<T[P]> };
declare var everythingPresent: EverythingPresent<Node>;
everythingPresent.maybe.property;
everythingPresent.leaf.maybe.property;
everythingPresent.leaf.leaf.maybe.property;
everythingPresent.leaf.leaf.leaf.maybe.property;
type OnlyLeafsPresent<T> = {
[P in keyof T]-?: T[P] extends Node
? OnlyLeafsPresent<Node>
: T[P]
};
declare var onlyLeafsPresent: OnlyLeafsPresent<Node>;
// These examples work fine
onlyLeafsPresent.maybe.property;
onlyLeafsPresent.leaf.maybe.property;
onlyLeafsPresent.leaf.leaf.maybe.property;
onlyLeafsPresent.leaf.leaf.leaf.maybe.property;
// Generic nested stuff
type GenericNode<T> = {
always: {
property: string;
}
maybe?: {
property: T;
}
leaf?: GenericNode<T>;
};
declare var everythingPresent2: EverythingPresent<GenericNode<string>>;
everythingPresent2.maybe.property;
everythingPresent2.leaf.maybe.property;
everythingPresent2.leaf.leaf.maybe.property;
everythingPresent2.leaf.leaf.leaf.maybe.property;
type OnlyLeafsPresentGeneric<T> = {
[P in keyof T]-?: T[P] extends GenericNode<infer U>
? OnlyLeafsPresentGeneric<GenericNode<U>>
: T[P]
};
declare var onlyLeafsPresent2: OnlyLeafsPresentGeneric<GenericNode<string>>;
// These examples work fine
onlyLeafsPresent2.maybe.property;
onlyLeafsPresent2.leaf.maybe.property;
onlyLeafsPresent2.leaf.leaf.maybe.property;
onlyLeafsPresent2.leaf.leaf.leaf.maybe.property; |
Note: since |
@Andy-MS Thanks, that's cleared things up a bit... it seems that the |
It looks like you can fix that by changing |
You're right - I could have sworn I tried that and it never helped. I've updated my original code example to what I actually wanted to achieve. It seems to work fine in 2.9.1 so I'm closing the issue. Sorry for taking your time! |
@Andy-MS so I've basically replicated the issue I was originally facing. If you had a moment to take a look, here's the code example that I'm having issues with. // Entities
type Order = {
id: number;
customer?: Entity<Customer>;
lineItems?: Entity<OrderLineItem[]>;
};
type Customer = {
name: string;
bestFriend?: Entity<Customer>;
legacyData?: {
registered: boolean;
};
};
type OrderLineItem = {
quantity: number;
options?: Entity<OrderLineItemOption[]>;
item?: Entity<Item>;
};
type OrderLineItemOption = {
colour: string;
};
type Item = {
description: string;
};
// Type helpers
type PropertiesWithoutNevers<T, U> = {
[P in keyof T]: T[P] extends U ? never : P
}[keyof T];
type Mandatory<T> = { [P in keyof T]-?: T[P] };
type Entity<T> = T & { _: "Entity" };
type EagerLoadedRelations<TEntity> = Pick<
Mandatory<TEntity>,
PropertiesWithoutNevers<
{
[P in keyof TEntity]-?: TEntity[P] extends Entity<infer TRelation> | undefined
? Entity<TRelation extends Array<infer TOneToMany> ? Array<Eager<TOneToMany>> : Eager<TRelation>>
: never
},
TEntity
>
>;
type NormalFields<TEntity> = Pick<
TEntity,
PropertiesWithoutNevers<
{ [P in keyof TEntity]-?: TEntity[P] extends Entity<infer U> | undefined ? never : TEntity[P] },
TEntity
>
>;
type Eager<T> = EagerLoadedRelations<T> & NormalFields<T>;
// Without Eager<T> - everything works as expected
declare var order: Order;
order.id; // works as expected
order.customer.name; // error as expected
order.lineItems[0].quantity; // error as expected
// With Eager<T> - Eager<T> doesn't seem to apply deeper than 1 level
declare var eagerOrder: Eager<Order>;
eagerOrder.id; // works as expected
eagerOrder.customer.name; // works as expected
eagerOrder.customer.bestFriend.name; // ERROR - doesn't work - bestFriend should be eager loaded
eagerOrder.customer.legacyData.registered; // errors as expected
eagerOrder.lineItems[0].quantity; // works as expected
eagerOrder.lineItems[0].item.description; // ERROR - doesn't work - items should be eager loaded
eagerOrder.lineItems[0].options[0].colour; // ERROR - doesn't work - options should be eager loaded |
Some things I noticed:
|
TypeScript Version: 2.9.1-insiders.20180521
Search Terms:
recursive inference
Code
Expected behavior:
I should only get an error where expected (1 line)
Actual behavior:
I get errors on the last 2 lines as well
Just to note - in 2.8.3 I also get errors for the last 3 lines of everythingPresent - so some improvements have been made but it's still not as expected
The text was updated successfully, but these errors were encountered: