簡體   English   中英

在打字稿中鍵入具有最大屬性數的動態鍵

[英]Type dynamic keys with max number of properties in typescript

我想知道是否可以在打字稿中鍵入對象中動態屬性的最大數量。

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

events.track('SOME_EVENT', { first: 'a', other: 'b', some: 'c'})

事件數據應該最多包含 3 個屬性及其各自的值,鍵也可以是動態的。

我用基本的Record輸入了它,但是允許的屬性數量沒有限制:

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

這可能嗎?

我想不出一種方法來聲明一個具有 1-3 個(但只有 1-3 個)未知字符串命名屬性的對象接口(但這並不意味着沒有;我只是在熟練工級別使用打字稿)。

我傾向於元組的聯合:

type EventParam = [name: string, value: string | number | unknown];
type EventParams = 
      [EventParam]
    | [EventParam, EventParam]
    | [EventParam, EventParam, EventParam];
export interface Events {
    track: (name: string, params?: EventParams) => void;
}

declare let events: Events;
// Works with 1:
events.track("something", [["first", "a"]]);
// Works with 2:
events.track("something", [["first", "a"], ["other", "b"]]);
// Works with 3:
events.track("something", [["first", "a"], ["other", "b"], ["some", "c"]]);
// Fails with 4:
events.track("something", [["first", "a"], ["other", "b"], ["some", "c"], ["fourth", 42]]);
// Error as desired −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^

游樂場鏈接

但這可能沒有最好的人體工程學。

我從這里得到了使用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>
) {}

我們基本上將所有鍵放入一個元組中,然后“手動”檢查元組的長度。 這可以很容易地擴展到其他數量的屬性,盡管它可能會變得丑陋。

一個缺點是錯誤消息:

類型“字符串”不可分配給類型“從不”。(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

操場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM