TypeScript:访问泛型对象以生成类型化函数
我有一个提供TypeScript:访问泛型对象以生成类型化函数,typescript,typescript-typings,Typescript,Typescript Typings,我有一个提供解码功能的接口 interface Converter<T> { uuid: CUUID; decode: (value: T) => Buffer; encode?: (value: Buffer) => T; } 这样我就可以将此类对象传递给服务: interface MyConverters extends Converters { state: Converter<string>; water: Converter&l
解码
功能的接口
interface Converter<T> {
uuid: CUUID;
decode: (value: T) => Buffer;
encode?: (value: Buffer) => T;
}
这样我就可以将此类对象传递给服务
:
interface MyConverters extends Converters {
state: Converter<string>;
water: Converter<number>;
}
const service = new Service<MyConverters>();
我希望name
是Converter
中的任意键,value
是decode
函数的ReturnType
,相应的Converter
就是Converter[name]
(因此基本上是Converter
的
)
这就是我最终得出的结论:
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 {}
}
我不知道发生了什么
最终,我想让这成为可能:
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
接口MyConverters扩展转换器{
状态:转换器;
水:转炉;
}
const service=新服务();
服务。写(“水”,12);
^ ^
检查这两种类型是否与MyConverter匹配
在开始之前,我们需要做几件事:
类型转换器={name:转换器
简言之,我放弃了
,转而支持条件推理。另外,我从扩展转换器
推断出转换器
,而不是T
,看看返回类型
在幕后是如何使用条件推理的。无论如何,这样做似乎更简单返回类型
如果您试图传递一个不是转换器的键,那么无论您提供什么值,您的
调用都不会编译。因此,在开始之前,我们需要做几件事:write
类型转换器={name:转换器
简言之,我放弃了
,转而支持条件推理。另外,我从扩展转换器
推断出转换器
,而不是T
,看看返回类型
在幕后是如何使用条件推理的。无论如何,这样做似乎更简单返回类型
如果您试图传递一个不是转换器的键,那么无论您提供什么值,您的
调用都不会编译。您遇到的第一个问题是write
转换器的外观。这只是一个类型为
转换器的
键的类型 编辑 @内河马达拉酒店♦ ConverterValue的版本比我的好,我会使用它名称
type ConverterValue<C extends Converters<keyof C>, N extends keyof C> = C[N] extends Converter<infer R> ? R : never;
您遇到的第一个问题是type ConverterValue=C[N]扩展转换器?R:从不;
转换器的外观。这只是一个带有
名称的类型
键的类型
转换器 编辑 @内河马达拉酒店♦ ConverterValue的版本比我的好,我会使用它
type ConverterValue<C extends Converters<keyof C>, N extends keyof C> = C[N] extends Converter<infer R> ? R : never;
你确定要type ConverterValue=C[N]扩展转换器?R:从不;
,因为它总是缓冲区。也许你的意思是ReturnType
?很抱歉,这是一个复制粘贴错误,实际上参数和返回类型是相反的。如果你改变你的答案,我可以改变我的问题来清理这个线程。我认为这对大部分答案没有多大关系我所做的编辑使参数的提取以任何一种方式工作。你确定你想要encode
,因为这将始终是缓冲区。也许你的意思是ReturnType
?很抱歉,这是一个复制粘贴错误,实际上参数和返回类型是相反的。如果你更改答案,我可以更改我的问题以清除此线程不要认为这对大部分答案有多大影响。我所做的编辑使参数的提取无论哪种方式都有效。@MadaraUchiha它不是真正的递归,把encode
看作是一个完全独立的类型,只是碰巧是keyof t
omg的键,你是上帝,这是有效的。我已经为此奋斗了很长时间了解决方案非常恰当。非常感谢你,伊玛接受了@MadaraUchiha的回答,因为它有点干净。不过,谢谢你!@Lukas你的电话,他的回答并不限制t
成为任何东西,这可能是好事,也可能是坏事thing@MadaraUchiha它不是真正的递归,可以将C
看作是一个完全的sep阿拉特类型,恰好是keyof T
omg的钥匙,你是上帝,这是有效的。我已经为此奋斗了这么长时间,解决方案非常正确。非常感谢你,伊玛接受@MadaraUchiha的答案,因为它有点干净。不过,谢谢你!@Lukas你的电话,他的答案并不限制T
,T帽子可以是好东西也可以是坏东西C
绝对更好,惭愧我没想到好吧,我很敬畏,你们太棒了!C[K]扩展转换器?R:never
绝对更好,惭愧我没想到好吧,我敬畏,你们太棒了!C[K]扩展转换器?R:never
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
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.
interface Converter<T> { uuid: CUUID; decode: (value: T) => Buffer; encode?: (value: Buffer) => T; } type Converters<K extends PropertyKey> = Record<K, Converter<any>> type ConverterValue<C extends Converters<keyof C>, N extends keyof C> = Parameters<C[N]["decode"]>[0]; class Service<C extends Converters<keyof C>> { public write<N extends keyof C>( name: N, value: ConverterValue<C, N> ): void {} } interface MyConverters extends Converters<keyof MyConverters> { state: Converter<string>; water: Converter<number>; } const service = new Service<MyConverters>(); service.write("water", 12); service.write("water", "12"); // err service.write("state", "");
type ConverterValue<C extends Converters<keyof C>, N extends keyof C> = C[N] extends Converter<infer R> ? R : never;