在打字稿中键入具有最大属性数量的动态键

Jos*_*des 2 javascript types typescript

我想知道是否可以在打字稿中键入对象中动态属性的最大数量。

所以基本的例子是跟踪事件:

events.track('SOME_EVENT', { first: 'a', other: 'b', some: 'c'})
Run Code Online (Sandbox Code Playgroud)

事件数据应该最多保存 3 个属性及其各自的值,键也可以是动态的。

我用 basic 键入它Record,但允许的属性数量没有限制:

export interface Events {
  track: (name: string, params?: Record<string, string | number | unknown>) => void;
}
Run Code Online (Sandbox Code Playgroud)

这可能吗?

Tob*_* S. 6

TuplifyUnion我从这里得到了一个解决方案:

我不确定这有多“安全”(请参阅​​免责声明)。使用TuplifyUnion被认为是不安全的,因为订单可能随时更改。由于这里的顺序并不重要,在这种情况下只有元素的数量很重要,所以我认为在这里使用这是可以的。

该解决方案允许 0-3 个键。如果您想要任何其他金额,只需将它们添加到联合中(例如1 | 2接受 1 或 2 个键)。

type UnionToIntersection<U> =
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type LastOf<T> =
  UnionToIntersection<T extends any ? () => T : never> extends () => (infer R) ? R : never

type Push<T extends any[], V> = [...T, V];

type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> =
  true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>


type MaxThreeProperties<T extends Record<string, any>> =
  TuplifyUnion<keyof T>["length"] extends 0 | 1 | 2 | 3 ? T : never
//    add all acceptable key amounts here ^   ^   ^   ^

function track<T extends Record<string, any>>(
  name: string, 
  params: MaxThreeProperties<T>
) {}
Run Code Online (Sandbox Code Playgroud)

我们基本上将所有键放入一个元组中,然后“手动”检查元组的长度。这可以很容易地扩展到其他数量的属性,尽管它可能会变得丑陋。

一个缺点是错误消息:

类型“string”不可分配给类型“never”。(2322)

这对于使用该功能的人来说可能会感到困惑......


以下是一些测试:

track('SOME_EVENT', {})                                  // works
track('SOME_EVENT', {a: ""})                             // works
track('SOME_EVENT', {a: "", b: ""})                      // works
track('SOME_EVENT', {a: "", b: "", c: ""})               // works
track('SOME_EVENT', {a: "", b: "", c: "", d: ""})        // ERROR
track('SOME_EVENT', {a: "", b: "", c: "", d: "", e: ""}) // ERROR

const a = {a: "", b: "", c: ""}
const b = {a: "", b: "", c: "", d: ""}

track('SOME_EVENT', a)  // works
track('SOME_EVENT', b)  // ERROR
Run Code Online (Sandbox Code Playgroud)

操场