简体   繁体   English

在 TypeScript 中,如何推断我的参数并强加约束,即所有项都是 T 的键,其中 T 是函数的泛型类型?

[英]In TypeScript, how can I infer my arguments and impose a constraint that all items be keyof T, where T is the generic type for the function?

My goal here is to create a function named: getFields .我的目标是创建一个名为: getFields的函数。 This function has a generic <T> and a parameter ...fields: Array<keyof T> .这个函数有一个通用的<T>和一个参数...fields: Array<keyof T> I would like this function to return a function which when given an object of type <T> will return a reduced object with only the properties named in ...fields .我希望这个函数返回一个函数,当给定一个<T>类型的对象时,该函数将返回一个简化的对象,其中只包含...fields命名的属性。

The following is one helper type and my getFields implementation:以下是一种辅助类型和我的getFields实现:

type SubObj<T, S extends Array<keyof T>> = Pick<
  T,
  keyof { [K in S[number]]: K extends keyof T ? K : never }
>;

export function getFields<T extends Record<string, unknown>>(
  ...fields: Array<keyof T>
): (obj: T) => SubObj<T, typeof fields> {
  return (obj: T) =>
    Object.fromEntries(fields.map((field) => [field, obj[field]])) as SubObj<
      T,
      typeof fields
    >;
}

I tested this implementation with the following code:我使用以下代码测试了这个实现:

type A = {
  a: string;
  b: string;
  c: string;
};

const b = getFields<A>('a', 'c')({ a: '', b: '', c: '' });

However, when I look at the typeof b it is Pick<A, "a" | "b" | "c">但是,当我查看typeof b它是Pick<A, "a" | "b" | "c"> Pick<A, "a" | "b" | "c"> Pick<A, "a" | "b" | "c"> . Pick<A, "a" | "b" | "c"> What I really want is Pick<A, "a" | "c">我真正想要的是Pick<A, "a" | "c"> Pick<A, "a" | "c"> . Pick<A, "a" | "c">

I have tried a lot of things to make this work the way I intend it to, but the only success was adding a second generic argument which would require me to change the code to this:我已经尝试了很多方法来使这项工作按照我想要的方式工作,但唯一的成功是添加了第二个通用参数,这需要我将代码更改为:

const b = getFields<A, ['a','c']>('a', 'c')({ a: '', b: '', c: '' });

This is too redundant for me to see as acceptable.这对我来说太多余了,无法接受。

At this point, I think I've hit the limits of my TypeScript abilities because I can't think of any other way to accomplish what I'm looking for.在这一点上,我认为我已经达到了我的 TypeScript 能力的极限,因为我想不出任何其他方法来完成我正在寻找的东西。

Is this even possible to do with TypeScript?这甚至可以用 TypeScript 做吗? If so, what do I need to do?如果是这样,我需要做什么?

TypeScript does not currently support partial type parameter inference (see microsoft/TypeScript#26242 ). TypeScript 目前不支持部分类型参数推断(请参阅microsoft/TypeScript#26242 )。 If you have multiple type parameters in a type/function, you either need to specify them all explicitly, or let them all be inferred.如果您在一个类型/函数中有多个类型参数,您要么需要明确指定它们,要么让它们全部被推断出来。 There is no way to specify one and let the other be inferred.没有办法指定一个并让另一个被推断出来。 If you want to go that route, there are workarounds, but then this question becomes a duplicate of other such questions, and I can point to, for example, this answer for how to proceed.如果你想走那条路,有一些解决方法,但是这个问题会成为其他此类问题的重复,例如,我可以指出如何继续的答案

Stepping back, though, I'd say that the example code here might possibly be expressed in a simpler way that doesn't require anyone specify any types at all.不过,退一步说,这里的示例代码可能会以更简单的方式表达,根本不需要任何人指定任何类型。 Consider this:考虑一下:

export function getFields<K extends PropertyKey>(
    ...fields: K[]
) {
    return <T extends Record<K, unknown>>(obj: T) =>
        Object.fromEntries(fields.map((field) => [field, obj[field]])) as Pick<T, K>;
}

Here we are completely removing the object type T from the call signature of getFields() .在这里,我们从getFields()的调用签名中完全删除了对象类型T All getFields() cares about is getting a list of key-like arguments.所有getFields()关心的是获取一个类似键的参数列表。 It then returns a function which is also generic , and this one cares about the object type T , and constrains it to be something with the keys from K .然后,它返回一个函数,它也是通用的,关于对象类型人关心T ,并约束它被什么东西从按键K Both T and K are therefore inferrable:因此TK都是可推断的:

const b = getFields('a', 'c')({ a: '', b: '', c: '' }); 
/* const b: Pick<{
    a: string;
    b: string;
    c: string;
}, "a" | "c"> */

Since the return value of getFields() is a generic function, it can be used for types other than A , for example:由于getFields()的返回值是一个泛型函数,因此它可以用于A以外A类型,例如:

const c = getFields('a', 'c')({ a: 1, b: 2, c: 3 }) // {a: number, c: number}

But should still error if you give it something inappropriate:但是如果你给它一些不合适的东西,它仍然会出错:

const d = getFields('a', 'c')({ a: 1 }) // error! property 'c' is missing

If you really care about specifying T you can do it when calling the return function:如果你真的关心指定T你可以在调用返回函数时这样做:

const e = getFields('a', 'c')<A>({ a: 1, b: 2, c: 3 }); // error!  number is not string

If for some reason you really want to specify T at the beginning and infer K , you need to use one of the workarounds for partial type inference, like even more currying :如果由于某种原因你真的想在开头指定T并推断K ,你需要使用部分类型推断的解决方法之一,比如更多的柯里化

const stricterGetFields = <T,>() => <K extends keyof T>(...fields: K[]) => (obj: T) =>
    Object.fromEntries(fields.map((field) => [field, obj[field]])) as Pick<T, K>;

const f = stricterGetFields<A>(); // specify here and do nothing else
const g = f('a', 'c')({ a: "", b: "", c: "" }); // Pick<A, 'a'|'c'>; 

Playground link to code Playground 链接到代码

暂无
暂无

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

相关问题 如果打字稿是使用`keyof`的泛型函数,为什么打字稿不能推断出它的类型? - Why can't typescript infer an argument's type if it is a generic function using `keyof`? TypeScript:推断通用 keyof 的类型 - TypeScript: Infer type of generic keyof 为什么 Typescript 不能推断嵌套泛型函数的类型? - Why can't Typescript infer the type of a nested generic function? Typescript有没有办法实例化一个Record<k, v> 通过通用分配 function<t> 其中:T 扩展了一个对象类型并且 K = keyof T?</t></k,> - Is there a way in Typescript to instantiate a Record<K, V> by assignment in a generic function<T> where: T extends an object-type and K = keyof T? 当 T 为条件时,TypeScript 无法推断泛型类型 - TypeScript can't infer generic type when T is conditional 如何正确推断 RxJS 主题的 T<T> 来自具有类型约束的泛型函数 - How to correctly infer T for an RxJS Subject<T> from generic function with type constraint typescript 通用约束 keyof T 和字符串:ts2322 - typescript generic constraint keyof T and string: ts2322 为什么TypeScript在嵌套对象中不能推断泛型类型? - Why can't TypeScript infer a generic type when it is in a nested object? 通用打字稿:来自 keyof T 值的通用类型 - Generic typescript: Generic type from keyof T values 为什么 typescript 不能正确推断 T[K]<t extends person, k keyof t> 通用的?</t> - Why typescript does not properly infer T[K] with <T extends Person, K extends keyof T> generic?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM