Reputation: 329
some context : playing with graphql I have pre-defined interfaces for query generated automatically, but the results of any given query is only a subset of that automatically-generated-interface
and to have a compile-time checking of query-results-interfaces I need an interface that is a custom subset ( STRICTLY without any additional parameters ) of a Super-interface,
an example...
type RecursivePartial<T> = {
[P in keyof T]?: RecursivePartial<T[P]>;
};
interface IAutogenerated {
name : string
weight: number
age: number
}
interface ICustom extends RecursivePartial<IAutogenerated> {
name: string
agez : number // <------ I want this not allowed at compiletime ( ie: because it's a typo!)
}
let a : ICustom = {
name : "me" // this is required, weight is not because the usage of "RecursivePartial"
}
in this example I want ICustom to be exactly a subset of IAutogenerated ( maybe with some creative usage of "keyof"?
in java I would use the override in each member of the extending interface to be sure to not add typo and to have the compiler help me during refactoring..
version of typescript: 3.3
thank you, Francesco
EDIT: given the answer of Tom I've added another ADDITIONAL EXAMPLE which may further expose the real usage of the RecursivePartial
// ------ AUTOGENERATED INTERFACE OF GRAPHQL -----
export interface People {
id: number;
name: string;
gender: Gender;
age: number;
childs: (Maybe<People>)[];
}
/// CUSTOMIZATION BASED ON SINGLE CREATED QUERY
export type Child = Pick<RecursivePartial<People>,
'name'
>
export type PeopleListItem = Pick<RecursivePartial<People>,
'id'|'name'|'childs' >
// what is needed here something between the Pick ( which allow strict subset ) and RecursivePartial, which allow super-typing of subset elements )
// export interface PeopleListItem extends RecursivePartial<People>{
// id : number,
// name : string,
// childs : Child[] // NOTE --> here Child is a subtype of People
// }
to give some context this will constitute the return type of gql:
query {
people {
id
name
childs {
name
}
}
here with the commented code I don't have the sub-type strictness of Pick, but i can ovverride members with "Partial"s with the Pick I cannot override elements but I have subtype strictness ..
seems a weird question but those constraint are both required to have a typed object sub-graph
EDIT 2 : I've created a monster that provide some of the requirements but it's very ugly , I'm using typescript since 1 week so please pardon me for the following code.. ( and please help me to find something better )
type RecursivePartial<T> = {
[P in keyof T]?: RecursivePartial<T[P]>;
};
type RecursivePartialPick<T, K extends keyof T> = {
[P in K]: RecursivePartial<T[P]>;
};
// ------ AUTOGENERATED INTERFACE OF GRAPHQL -----
export interface People {
id: number;
name: string;
gender: Gender;
age: number;
childs: (Maybe<People>)[];
}
/// CUSTOMIZATION BASED ON SINGLE CREATED QUERY
export type Child = RecursivePartialPick<People, 'name' >
// this will stabilize sub-fields Picke'd from the original type (Avoid typing errors and code duplication )
type _PeoplePick = 'id' | 'name' | 'childs';
// override the field with a subtype
interface _PeopleListItem extends RecursivePartialPick<People,_PeoplePick >{
childs : Child[] //<<--- note here : no safety against typing errors in "childs" field name ( Except that resulting type is not Child[] but (Maybe<People>)[];
}
export type PeopleListItem = Pick<_PeopleListItem,_PeoplePick>
let result : PeopleListItem = {
name : "" ,
id : 2 ,
childs : [{ // <Child[]>
name : "n"
}]
}
Upvotes: 2
Views: 890
Reputation: 1168
type Custom = Pick<RecursivePartial<IAutogenerated>, 'name' | 'age'>; // OK
type Custom2 = Pick<RecursivePartial<IAutogenerated>, 'name' | 'agez'>; // Type error
Upvotes: 2