【问题标题】:Typescript - How to make values to equal the keys of an object?Typescript - 如何使值等于对象的键?
【发布时间】:2022-01-09 17:22:10
【问题描述】:

我想键入一个键值相同的对象:

const myObj = {
    FOO: 'FOO',
    BAR: 'BAR'
};

我尝试使用myObj 和key 设置typeof:

const actions: { [x: string]: x } = { // 'x' refers to a value, but is being used as a type here. Did you mean 'typeof x'?
    set: 'set1'
}

const actions: { [x: string]: typeof x } = {
    set: 'set1'  // doesn't trigger
}

const actions: { [p: string]: keyof typeof actions } = {
    set: 'set' // Type 'string' is not assignable to type 'never'.
}

type K = 'set' | 'set2';
const actions: { [p in K]: K } = { // triggers missing set2
    set: 'set1' // doesn't trigger
}

有没有一种方法可以确保键和值始终匹配?蒂亚!

【问题讨论】:

  • Set 对象只有 key 属性,您也可以将其用作值
  • @Berkays 你能举个例子吗?我以前没有在 typescript 中使用过 Set ..

标签: javascript typescript types


【解决方案1】:

您可以通过创建一个接收对象的辅助函数来执行此操作,然后通过生成额外的参数来对其进行 TypeScript 检查,如果给定的对象没有通过我们相同的键/值法则,这些参数将使您的代码失败。

// basically, we create an extra parameter when the object is not valid
function createSamePairedObject<T extends Readonly<Record<PropertyKey, PropertyKey>>>(obj: T, ..._lockParams: T extends { [K in keyof T]: K } ? [] : ["INVALID_PAIRED_OBJECT"]): T {
  return obj as any;
}

// PASS
const a = createSamePairedObject({ // { readonly a: "a" }
  a: "a",
} as const);

// FAIL - "b" != "bb"
const b = createSamePairedObject({
  a: "a",
  b: "bb",
} as const);

// FAIL - not const object
const c = createSamePairedObject({
  [5]: 5,
});

// PASS
const d = createSamePairedObject({
  [5]: 5,
} as const);

TypeScript Playground Link

【讨论】:

  • 不只是为了类型检查而运行一个函数吗? typescript 应该是静态的,但是有了函数,我会在运行时不必要地浪费 CPU 周期..
  • @GopikrishnaS 也许,但这是您问题 IMO 的最佳解决方案。另一种方法是使用不会影响运行时的类型断言,但这会非常难看。在我的基准测试中,似乎大多数 JS 引擎优化了采用单个参数然后返回它的函数,因为与常规对象方法相比,map 函数得到了 +-5%,因此它对您的代码几乎没有影响。 jsbench.me/enky7kb166/1
  • 我想如果你有一个未知的键列表是有意义的
  • @GopikrishnaS 不,这在所有情况下都应该有意义,因为您不需要在每次添加新密钥时都更新密钥列表。它会根据您的代码自动更新。
  • 我似乎无法修复第二个示例。即使将 b 更改为 bb 我仍然收到错误消息:Expected 2 arguments, but got 1. Arguments for the rest parameter '_lockParams' were not provided
【解决方案2】:

玩了一会儿就知道了:

type K = 'set' | 'set2';
const actions: { [p in K]: p } = { // note that I am using p instead of K from the question
    set: 'set1'
}

使用此设置,我收到以下错误:

TS2741: Property 'set2' is missing in type '{ set: "set"; }' but required in type '{ set: "set"; set2: "set2"; }'.

TS2322: Type '"set1"' is not assignable to type '"set"'.

以下是让它快乐的原因:

type K = 'set' | 'set2';
const actions: { [p in K]: p } = {
    set: 'set',
    set2: 'set2'
}

更新:如果您有一个已知的键列表,这可以工作,但如果您有一个未知的键列表或将任何键与其值匹配,请关注@sno2 的answer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 2020-12-08
    • 2021-12-08
    • 2020-05-14
    相关资源
    最近更新 更多