简体   繁体   English

通过 object 属性推断条件返回泛型类型

[英]Infer conditional return generic types by object property

I am trying to infer the generic type of Model per property.我正在尝试推断每个属性的通用类型Model Everything currently is showing as unknown[] instead of the desired types in the comments below.当前所有内容都显示为unknown[]而不是下面评论中所需的类型。

playground 操场

 class Model<T> { x?: T } type ArgumentType<T> = T extends Model<infer TInner>? Model<TInner>: ( T extends Model<infer TInner>[]? Model<TInner>[]: never ); type ReturnType<T> = T extends Model<infer TInner>? TInner[]: ( T extends Model<infer TInner>[]? TInner[][]: never ); const test = <TInner, TValue extends ArgumentType<TInner>, T extends Record<string, TValue>>(models: T): Record<keyof T, ReturnType<TValue>> => { return; } const numberModel = new Model<number>(); const stringModel = new Model<string>(); const bigintModel = new Model<bigint>(); const result = test({ prop1: [numberModel, numberModel, numberModel], prop2: [stringModel], prop3: stringModel, prop4: [numberModel, numberModel, numberModel, bigintModel], prop5: stringModel }); //expected types result.prop1 // number[][] result.prop2 // string[][] result.prop3 // string[] result.prop4 // (number | bigint)[][] result.prop5 // string[] //actual types result.prop1 // unknown[] result.prop2 // unknown[] result.prop3 // unknown[] result.prop4 // unknown[] result.prop5 // unknown[]

My suggestion for your test() function would be to give it the following call signature:我对你的test() function 的建议是给它以下调用签名:

declare const test: <T extends Record<keyof T, Model<any> | Model<any>[]>>(
  models: T
) => { [K in keyof T]:
    T[K] extends Model<infer U> ? U[] :
    T[K] extends Model<infer U>[] ? U[][] :
    never
  }

Note here that we have just a single generic type parameter T , correponding exactly to the type passed in for the models function parameter.请注意,我们只有一个泛型类型参数T ,与为models function 参数传入的类型完全对应。 This T is constrained to Record<keyof T, Model<any> | Model<any>[]>T限制Record<keyof T, Model<any> | Model<any>[]> Record<keyof T, Model<any> | Model<any>[]> , meaning that it can have any keys whatsoever, but its property values must all either be a Model<X> for some X , or an array of Model<X> for some X . Record<keyof T, Model<any> | Model<any>[]> ,这意味着它可以有任何键,但它的属性值必须全部是某个 X 的Model<X>或某个XModel<X> X This is a fairly direct and specific constraint.这是一个相当直接和具体的约束。

In your original version you had three type parameters, each of which was constrained to some type function of another, but TypeScript's compiler is unable to do inference that way.在您的原始版本中,您有三个类型参数,每个参数都被限制为另一个类型的某种类型 function,但是 TypeScript 的编译器无法以这种方式进行推理。 If you have type parameters U, V extends F<U>, W extends F<V> you might get inference if you give the compiler a value of type U , but it is essentially impossible to do it if you only give the compiler a value of type W .如果你有类型参数U, V extends F<U>, W extends F<V>如果你给编译器一个U类型的值,你可能会得到推断,但是如果你只给编译器一个类型W的值。 It can't run the engine backwards to make W do something to V and then make V do something to U .它不能向后运行引擎来让WV做某事,然后让VU做某事。 A single type parameter is a lot easier to work with.使用单个类型参数要容易得多。

Then note that the output type然后注意 output 类型

{ [K in keyof T]:
    T[K] extends Model<infer U> ? U[] :
    T[K] extends Model<infer U>[] ? U[][] :
    never
}

is essentially your ( unfortunately named ) ReturnType<> type alias but mapped over the properties of T .本质上是您的( 不幸命名的) ReturnType<>类型别名,但映射到T的属性上。 For each property key K in the type T corresponding to models , we take the property value type T[K] and do something like your ReturnType<T[K]> .对于对应于models的类型T中的每个属性键K ,我们采用属性值类型T[K]并执行类似于您的ReturnType<T[K]>的操作。


Let's test it out:让我们测试一下:

const numberModel = new Model<number>();
const stringModel = new Model<string>();
const bigintModel = new Model<bigint>();

const result = test({
  prop1: [numberModel, numberModel, numberModel],
  prop2: [stringModel],
  prop3: stringModel,
  prop4: [numberModel, numberModel, numberModel, bigintModel],
  prop5: stringModel
});

/* const result: {
    prop1: number[][];
    prop2: string[][];
    prop3: string[];
    prop4: (number | bigint)[][];
    prop5: string[];
} */

Looks good!看起来挺好的!

Playground link to code 游乐场代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM