如何创建一个接口作为另一个接口的子集?

时间:2019-03-13 16:46:24

标签: typescript typescript-typings

一些上下文:使用graphql我有用于自动生成查询的预定义接口,但是任何给定查询的结果只是该自动生成接口的子集

并且要对查询结果接口进行编译时检查,我需要一个接口,该接口是超级接口的自定义子集(严格没有任何其他参数),

一个例子...


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"
}

在此示例中,我希望ICustom完全是IAutoGenerated的子集(也许具有一些创造性的“ keyof”用法?

在Java中,我将在扩展接口的每个成员中使用重写,以确保不添加错字并在重构期间让编译器帮助我。.

打字稿的版本:3.3

谢谢你, 弗朗切斯科

编辑: 给定汤姆的答案,我添加了另一个示例,它可能进一步揭示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
// }

为了提供一些上下文,这将构成gql的返回类型:

query {
people {
 id
 name
 childs {
   name 
 } 
}

此处带有注释的代码,我没有Pick的子类型严格性, 但是我可以使用Pick来用“ Partial”来代替成员,我不能覆盖元素,但是我有严格的子类型..

似乎有一个怪异的问题,但是这些约束都必须具有类型化的对象子图

编辑2: 我创建了一个提供一些要求的怪物,但是它非常丑陋,自1周以来我一直在使用打字稿,所以请原谅以下代码。(并请帮助我找到更好的东西)


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"
   }]
}

1 个答案:

答案 0 :(得分:1)

type Custom = Pick<RecursivePartial<IAutogenerated>, 'name' | 'age'>; // OK
type Custom2 = Pick<RecursivePartial<IAutogenerated>, 'name' | 'agez'>; // Type error