对象文字,它实现一个接口,该接口又使用通用方法

时间:2019-08-14 20:07:41

标签: typescript typescript2.0

我具有以下自定义类型和接口:

export type MultiMedia = 'image' | 'audio' | 'video';
export type FieldType = 'string' | 'number' | 'boolean' | MultiMedia;

export interface Field {
  name: string,
  label: string,
  type: FieldType,
  validator: <T>(val: T) => boolean,
  bounds: { lower: number; upper: number }
}

export interface Theme {
  title: string,
  logoPath: string,
  tags: string[],
  fields: Field[]
}

由于字段类型彼此不同,因此我在validator接口中将Field定义为通用方法。当我想制作实现Field接口打字稿的对象文字时

  

类型'(val:string)=>布尔值'不能分配给类型'(val:T)=>布尔值。

const fields: Field[] = [
  {
    name: "firstName",
    label: "First Name",
    type: "string",
    bounds: { lower: 1, upper: 1 },
    validator: (val: string) => {
     return val.length > 20;
    }
  }

我可以按以下方式更改Field界面来解决该问题。

export interface Field<T> {
  name: string,
  label: string,
  type: FieldType,
  validator: (val: T) => boolean,
  bounds: { lower: number; upper: number }
}

但是打字稿抱怨fields界面中的Theme属性。

  

通用类型“字段”需要1个类型参数。

2 个答案:

答案 0 :(得分:1)

我认为这里的问题是Field基本上是union,因为您希望它是或者string字段, number字段等。我这样做的方法是创建一个通用的SpecificField<F>接口,该接口表示从每个字段类型F到其验证器的约束,以及然后将Field用作所有SpecificField<F>类型的并集的类型别名:

首先让我们定义字段映射,以便我们知道验证器应接受的内容

interface FieldMapping {
  image: HTMLImageElement; // guessing
  audio: HTMLAudioElement; // guessing
  video: HTMLVideoElement; // guessing
  string: string;
  number: number;
  boolean: boolean;
}

现在是SpecificField<F>界面:

export interface SpecificField<F extends FieldType> {
  name: string;
  label: string;
  type: F;
  validator: (val: FieldMapping[F]) => boolean;
  bounds: { lower: number; upper: number };
}

您可以看到SpecificField<string>的{​​{1}}中的type和仅接受"string"值的validator。然后我们将string变成一个并集,这可能是这样的:

Field

这使用mapped type获取每个字段作为属性,然后通过looking up获取所有属性的并集。您可以验证其计算结果为:

type Field = { [F in FieldType]: SpecificField<F> }[FieldType];

然后,您可以验证以下各项是否有效:

type Field = SpecificField<"string"> | SpecificField<"number"> |
  SpecificField<"boolean"> | SpecificField<"image"> | SpecificField<"audio"> | 
  SpecificField<"video">

好的,希望能有所帮助;祝你好运!

Link to code

答案 1 :(得分:0)

您的最后一个示例将起作用,除了在使用T接口时(在Field接口声明和常量{{1中)都需要声明Theme的类型。 }}声明),而不是在声明fields时:

validator

编辑:

此外,如果要将export type MultiMedia = 'image' | 'audio' | 'video'; export type FieldType = 'string' | 'number' | 'boolean' | MultiMedia; export interface Field<T> { name: string, label: string, type: FieldType, validator: (val: T) => boolean, bounds: { lower: number; upper: number } } export interface Theme { title: string, logoPath: string, tags: string[], fields: Field<string>[] } const fields: Field<string>[] = [ { name: "firstName", label: "First Name", type: "string", bounds: { lower: 1, upper: 1 }, validator: (val: string) => { return val.length > 20; } } ] 的类型限制为T之一,则可以执行以下操作:

FieldType