typescript - TypeScript:访问泛型对象以生成类型化函数
问题描述
我有一个提供decode
功能的界面
interface Converter<T> {
uuid: CUUID;
decode: (value: T) => Buffer;
encode?: (value: Buffer) => T;
}
不,我有一个名为的类Service
,它提供了一个包含任意数量的这些转换器的对象:
type Converters = { name: Converter<any> };
class Service<C extends Converters> {
}
这样我就可以将这些对象传递给Service
:
interface MyConverters extends Converters {
state: Converter<string>;
water: Converter<number>;
}
const service = new Service<MyConverters>();
该类Service
有几个函数应该在传递给转换器Converters
的 Generic T
( ) 上工作。Converter<T>
所以不要这样做:
class Service<C extends Converters> {
public write(name: string, value: any): void {
}
}
我希望name
成为任何关键,Converters
并value
成为对应ReturnType
的功能(所以基本上是of )。decode
Converter
Converters[name]
<T>
Converter<T>
这就是我最终想出的:
interface Converter<T> {
uuid: CUUID;
decode: (value: T) => Buffer;
encode?: (value: Buffer) => T;
}
type Converters = { name: Converter<any> };
type ConverterNames<C extends Converters> = keyof C;
type ConverterValue<C extends Converters, N extends Keys<C>> = ReturnType<C[N]["decode"]>;
class Service<C extends Converters> {
public write<N extends ConverterNames<C>>(
name: N,
value: ConverterValue<C, N>
): void {}
}
…但它不起作用
type ConverterValue<C extends Converters, N extends ConverterNames<C>> = ReturnType<C[N]["decode"]>;
^^^^^^^^^^^^^^
我收到错误
Type 'C[N]["decode"]' does not satisfy the constraint '(...args: any) => any'. Type 'C[keyof C]["decode"]' is not assignable to type '(...args: any) => any'. Type 'C[string]["decode"] | C[number]["decode"] | C[symbol]["decode"]' is not assignable to type '(...args: any) => any'. Type 'C[string]["decode"]' is not assignable to type '(...args: any) => any'.ts(2344) Type '"decode"' cannot be used to index type 'C[N]'.ts(2536)
而且我不确定发生了什么。
最终我想让这成为可能:
interface MyConverters extends Converters {
state: Converter<string>;
water: Converter<number>;
}
const service = new Service<MyConverters>();
service.write("water", 12);
^ ^
checks if these 2 types match MyConverters
解决方案
所以在我们开始之前有几件事:
type Converters = { name: Converter<any> };
不是一个键映射到 aConverter<any>
的对象,它是一个键映射name
到a 的对象Converter<any>
,我怀疑你想要类似的东西type Converters = { [name: string]: Converter<any>; }
,但这也行不通。见下文。- 我认为不可能将泛型限制为,
{ [name: string]: Converter<any>; }
因为任何扩展类型都需要提供索引签名(即允许访问任何字符串,这不是您想要的。
我来过的最好的是
interface Converter<T> {
uuid: CUUID;
decode: (value: T) => Buffer;
encode?: (value: Buffer) => T;
}
class Service<C> {
public write<K extends keyof C>(
name: K,
value: C[K] extends Converter<infer R> ? R : never
): void { }
}
interface MyConverters {
state: Converter<string>;
water: Converter<number>;
}
const service = new Service<MyConverters>();
service.write('water', 'foo'); // Error, expected number.
简而言之,我放弃了extends Converters
支持条件推理。另外,我在推断T
fromConverter<T>
而不是ReturnType<Converter<T>['decoder']>
,看看如何ReturnType
在幕后使用条件推断,这种方式似乎更简单。
如果您尝试传递不是 Converter 的密钥,write
则无论您提供什么值,您的调用都不会编译。
推荐阅读
- java - 如何使用 java.beans.PropertyDescriptor 将对象属性值更新为 null
- vue.js - 使用 vuetify 更改单个 vue 组件中的字体
- python - 创建函数以在特定列上合并给定数量的数据框
- reactjs - React Native 搜索栏调度 API 调用
- python - 如何将源添加到手动创建的模块?
- python - tkinter 中的画布无法通过按键功能更改
- node.js - 当我尝试实现身份验证时出现 Firebase.app() 错误
- python - 读取python文件的一部分
- python - 如果子字符串是字符串的一部分,则使用过滤器函数返回完整的字符串
- javascript - 为什么我的 setState() 在我的代码中表现得不可预测?