输入保护通用的类型并将其定义为可选

时间:2019-09-11 12:27:14

标签: typescript

我有一个接受通用的类

interface Converter<T = Buffer> {
  uuid: string;
  decode?: (value: Buffer) => T;
  encode?: (value: T) => Buffer;
}

type Converters = Record<string, Converter<any>>;

export default class Service<C extends Converters> {
  private converters?: Converters;

  constructor(converters?: C) {
    this.converters = converters;
  }
}

这个想法是,使用构造函数,Converter<T>类可以使用任何类型的Service。所以我可以这样做:

// Converters using Converter<string>
const converters = {
  manufacturer: {
    uuid: "2a29",
    decode: (buffer: Buffer) => buffer.toString()
  },
}

const service = new Service(converters);

这个

// Converters using Converter<number>
const converters = {
  model: {
    uuid: "2a24",
    decode: (buffer: Buffer) => buffer.readInt8(0)
  }
}

const service = new Service(converters);

这个

// Converters using Converter<string> and Converter<number>
const converters = {
  manufacturer: {
    uuid: "2a29",
    decode: (buffer: Buffer) => buffer.toString()
  },
  model: {
    uuid: "2a24",
    decode: (buffer: Buffer) => buffer.readInt8(0)
  }
}

const service = new Service(converters);

或者只是这个

const service = new Service();

因为转换器是可选的。

现在,这里的问题是Service类具有一个名为read的方法,该方法将接受一个名为name的参数并返回一个值,并且类型name并且返回类型应基于

  • 哪些转换器已传递给Service
  • 是否有任何转换器已经传递给Service

如果提供了转换器

  • read应该仅接受转换器的键作为name参数
  • read应返回与该名称对应的转换器的泛型类型

如果未传递任何转换器,则read应该接受任何字符串作为参数并返回Buffer

所以,如果我通过

const converters = {
  manufacturer: {
    uuid: "2a29",
    decode: (buffer: Buffer) => buffer.toString()
  },
  model: {
    uuid: "2a24",
    decode: (buffer: Buffer) => buffer.readInt8(0)
  }
}

const service = new Service(converters);
const serviceNoConverter = new Service();

这应该发生

const value = service.read("manufacturer");
//    ^^^^^ type string

const value = service.read("model");
//    ^^^^^ type number

const value = service.read("aassd");
//                          ^^^^^ type error, not manufacturer or model

const value = serviceNoConverter.read("asdasdasd")
//    ^^^^^ type Buffer                ^^^^^^^^^ any string is allowed

因此,在StackOverflow的帮助下(尤其是jcalz,感谢伙计们),我可以做到这一点:

?

? Link to playground

这里的所有内容都完全符合描述,但是,您可以在

处看到它
constructor(converters?: C) {
  this.converters = converters;
}

存在一个错误,其中convertersthis.converters不匹配,因为converters的类型this.converters不受Converters的类型保护。但是我不能将通用类型作为

Service<C extends Converters>

因为这将破坏如上所述的read的功能。

所以我的问题是,如何在仍然保留此功能并将其设置为可选的同时,对参数进行类型保护?

2 个答案:

答案 0 :(得分:2)

我认为将VARCHAR2约束为COALESCE(TO_CHAR(column), ' ') like '%' ,并将C约束为默认值应该可行。我也建议将成员变量更改为Converters | undefined类型,因为它已经受到了适当的约束:

undefined

此处的关键是,通过将默认值设置为C,创建没有转换器的服务将导致类型:class Service<C extends Converters | undefined = undefined> { private converters?: C; constructor(converters?: C) { this.converters = converters; } //... } 而不是undefined

Playground

答案 1 :(得分:0)

Here you go

最初在操场上出现的问题是:  -太复杂了。  -Andhra Pradesh 609949.85 Bihar 413513.59 Chhattisgarh 260786.98 Assam 224247.19 Goa 45012.75 Arunachal Pradesh 18796.07 属性类型。

lukasgeiter 指出,converters的类型应为C。 但是,converters的默认通用值不是必需的。 这样也可以很好地工作:

undefined