【问题标题】:how to create an interface to be a subset of another interface?如何创建一个接口成为另一个接口的子集?
【发布时间】:2019-03-14 04:02:16
【问题描述】:

一些上下文:使用 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"
   }]
}

【问题讨论】:

  • 我想补充一点,这对我来说不再是问题,我还没有找到这个“受限子类型定义”的解决方案,但是对于 graphql 查询,我现在正在生成专用(新)使用该库中的“typescript-client”插件为每个查询类型图(非子类型):https://graphql-code-generator.com/docs/plugins/

标签: typescript typescript-typings


【解决方案1】:
type Custom = Pick<RecursivePartial<IAutogenerated>, 'name' | 'age'>; // OK
type Custom2 = Pick<RecursivePartial<IAutogenerated>, 'name' | 'agez'>; // Type error

【讨论】:

  • 我认为更多的解释会让学习者的答案更清楚。仅代码答案并不总是有用的。
  • 对不起,这几乎没问题,问题是我不能在这里使用 RecursivePartial 接口,因为我无法覆盖包含的类型(Pick'ed),一切都需要覆盖返回的 graphql 查询类型在打字稿中...也许我会准备更完整的示例并编辑原始问题..
猜你喜欢
  • 2012-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-21
  • 1970-01-01
  • 2014-09-16
  • 1970-01-01
  • 2019-02-20
相关资源
最近更新 更多