键入接口引用不同类型的结构?

时间:2017-04-21 18:19:14

标签: typescript typescript2.0

我的目标是创建一个类型接口,该接口具有名称在不同接口中定义的属性。

我对typescript中的模型架构对象有以下定义。

export interface ModelSchema {
  idAttribute: string;
  name: string;
  attributes: {
    [attrName: string]:
      { type: 'number', default?: number, readOnly?: boolean} |
      { type: 'string', default?: string, readOnly?: boolean} |
      { type: 'boolean', default?: boolean, readOnly?: boolean} |
      { type: 'date', default?: Date, readOnly?: boolean} |
      { type: 'array', default?: string[] | number[], readOnly?: boolean } |
      { type: 'object', default?: object, readOnly?: boolean}
  };
  relationships: {
    [relName: string]: {
      type: RelationshipSchema,
      readOnly?: boolean,
    },
  };
};

我们在这里讨论的关键是关系属性。它可以包含任意数量的属性,每个属性都有一个字符串名称(' children',' reply'等),每个属性代表数据模型中的has-many关系。

我想为审批者定义一个单独的容器 - 服务器可以询问的内容"该用户是否允许C / R / U / D该项/关系?"结构是平行的,因为每个关系都有不同的规则,每个关系都有自己的批准方法。

所以,理想情况下,我会说

之类的话
export interface ApproverDefinition<S extends ModelSchema> {
  typeName: string,
  attributes: AttributesAuthorize,
  relationships: {
    [name: string]: RelationshipAuthorize,
  }
}

然后在那里有一个单独的警卫,它基本上说:&#34; ApproverDefinition.relationships的字符串索引属性需要与S的关系属性具有相同的名称,ModelSchema通常与此相关到。

像(伪代码):

export interface ApproverDefinition<S extends ModelSchema> {
  typeName: string,
  attributes: AttributesAuthorize,
  relationships: {
    [name in keyof S.relationships]: RelationshipAuthorize,
  }
}

以上几乎可以工作(除了它不需要完全覆盖,但我会接受它) - 我觉得它解释了我想要做什么,但我从TS得到两个错误。首先,我在界面上导出S私有名称,其次是我将S视为命名空间。

我需要/希望保持批准者代码与架构代码不同的原因有很多,所以在这里扩展ModelSchema并不是真的可行。

我可以进行运行时类型检查,如果我基本上检查以确保Object.keys(approver.relationships)和Object.keys(model.relationships)具有相同的条目,但我有点想要捕获它打字稿语言。

是否可以做这样的事情?

编辑:这是一个示例模型架构:

const ProfileSchema = {
  idAttribute: 'id',
  name: 'profiles',
  attributes: {
    id: { type: 'number', readOnly: true },
    short_text: { type: 'string', readOnly: false },
    long_text: { type: 'string', readOnly: true },
    // SNIP ...
  },
  relationships: {
    memberships: { type: Memberships, readOnly: false },
    conversations: { type: ProfilePermissions, readOnly: false },
    followingProfiles: { type: FollowingProfiles, readOnly: false},
    followingDocuments: { type: FollowingDocuments, readOnly: false},
    followingCommunities: { type: FollowingCommunities, readOnly: false},
    followers: { type: FollowingProfiles, readOnly: false},
  },
};

我想定义

const ProfileApprover: ApproverDefinition<ProfileSchema> = {
  typeName: 'profiles'
  attributes: /* attribute approver */
  relationships: {
    memberships: /* approver function */,
    conversations: /* approver function */,
    followingProfiles: /* approver function */,
    followingDocuments: /* approver function */,
    followingCommunities: /* approver function */,
    followers: /* approver function */,
  }
}

请注意,ProfileApprover.relationships与ProfileSchema.relationships具有相同的属性,但属性具有不同的值。这就是我要在类型规则中指定的 - 所有Approver实例都与其对应的模式匹配。

如果他们不在那里注册批准者,我总是会抛出运行时错误,但这感觉就像我应该能够静态地定义打字稿一样。

1 个答案:

答案 0 :(得分:1)

如果我理解正确,你想要的是这样的

首先,我们将ModelShema的relationships属性的类型提取到一个接口中,以便我们可以独立引用它

library(splitstackshape)
dcast(cSplit(df, "sick", " ", "long")[, sick:= factor(sick, levels = 
    c("diarrhoea", "cough", "malaria"))], x~sick, value.var = "sick", drop = FALSE)[,
       sick := df$sick][]

我们在ModelSchema中使用此接口代替以前的对象文字类型

export interface Relationships {
  [relName: string]: {
    type: RelationshipSchema,
    readOnly?: boolean,
  },
}

由于ApproverDefinition只引用ModelSchema的relationship属性,我们可以使用它现在可用的类型作为约束。这使我们可以访问keyof

使用的密钥
export interface ModelSchema {
  idAttribute: string;
  name: string;
  attributes: {
    [attrName: string]:
    {type: 'number', default?: number, readOnly?: boolean} |
    {type: 'string', default?: string, readOnly?: boolean} |
    {type: 'boolean', default?: boolean, readOnly?: boolean} |
    {type: 'date', default?: Date, readOnly?: boolean} |
    {type: 'array', default?: string[] | number[], readOnly?: boolean} |
    {type: 'object', default?: object, readOnly?: boolean}
  };
  retationships: Relationships;
}

最后,由于ProfileSchema是一个值而不是一个类型,我们需要在其relationships属性上使用typeof并将结果用作ApproverDefinition的类型参数

export interface ApproverDefinition<R extends Relationships> {
  typeName: string;
  attributes: AttributesAuthorize;
  relationships: {
    [name in keyof R]: RelationshipAuthorize
  }
}

const ProfileSchema = {
  idAttribute: 'id',
  name: 'profiles',
  attributes: {
    id: {type: 'number', readOnly: true},
    short_text: {type: 'string', readOnly: false},
    long_text: {type: 'string', readOnly: true},
    // SNIP ...
  },
  relationships: {
    memberships: {type: Memberships, readOnly: false},
    conversations: {type: ProfilePermissions, readOnly: false},
    followingProfiles: {type: FollowingProfiles, readOnly: false},
    followingDocuments: {type: FollowingDocuments, readOnly: false},
    followingCommunities: {type: FollowingCommunities, readOnly: false},
    followers: {type: FollowingProfiles, readOnly: false},
  },
};