[英]Type guarding a generic and defining it as optional
我有一個接受通用的課程
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
類 如果提供了轉換器
name
參數 如果未傳遞任何轉換器,則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,感謝伙計們),我做到了:
👇
此處的所有內容均完全按照說明運行, 但您可以在上看到
constructor(converters?: C) {
this.converters = converters;
}
有一個錯誤的converters
不匹配this.converters
因為converters
不是類型守衛,而this.converters
是該類型的Converters
。 但是我不能將泛型作為
Service<C extends Converters>
因為那樣會破壞read
的功能。
所以我的問題是,如何在仍然保留此功能並將其設為可選的同時,對參數進行類型保護?
我認為將C
限制為Converters | undefined
Converters | undefined
和undefined
因為默認值應該起作用。 我也建議將成員變量更改為C
類型,因為它已受到適當的約束:
class Service<C extends Converters | undefined = undefined> {
private converters?: C;
constructor(converters?: C) {
this.converters = converters;
}
//...
}
此處的關鍵是,通過將默認值設置為undefined
,創建不帶轉換器的服務將導致以下類型: Service<undefined>
而不是Service<Record<...> | undefined>
Service<Record<...> | undefined>
給你 。
操場上最初的問題是:-過度復雜化。 - converters
屬性類型。
正如lukasgeiter指出的那樣, converters
應為C類型。但是,不需要默認的通用值undefined
。 這樣也可以很好地工作:
...
class Service<C extends Converters> {
private converters?: C;
constructor(converters?: C) {
this.converters = converters;
}
public read<N extends keyof C>(name: N): C[N] {
...
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.