如何使用TypeScript断言对象仅具有来自字符串联合的属性?

huangapple go评论65阅读模式
英文:

How do I assert an ojbect to only have properties from a string union with TypeScript?

问题

Here's the translated code portion:

这是一个示例

type supportedChains = 'eth_mainnet' | 'eth_testnet'

// 我想确保 fixtures 只有 eth_mainnet 和 eth_testnet 属性
const fixtures = {
    eth_testnet: {
        // ...
    },
} as { [chain in supportedChains]: any }

If you need further assistance with this code or additional reading material, please let me know.

英文:

Here's an example:

type supportedChains = 'eth_mainnet' | 'eth_testnet'

// I want to make sure fixtures only have eth_mainnet and eth_testnet props
const fixtures = {
    eth_testnet: {
        // ...
    },
} as ??

What I've tried for ??:

  • initially { [chain: supportedChain]: any } – getting An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.ts(1337)
  • next, { [chain in supportedChain]: any } – this doesn't give an error, but also doesn't guard against unwanted props

Not sure how to seach for this, please suggest how to implement this and ideally some further reading.

答案1

得分: 1

You should use satisfies operator for this and additionally adding const assertion would be great:

const fixtures = {
   eth_mainnet: 'some value',
   eth_testnet: 'some value 2',
} as const satisfies Record<supportedChains, string>

The benefit of this approach is that it prevents the compiler from widening the type of the fixtures. With regular type definition, the type of fixtures will be: Record<supportedChains, string>, however, with the satisfies and const assertion, it will take the exact values from the object:

{
   eth_mainnet: 'some value',
   eth_testnet: 'some value 2',
}
英文:

You should use satisfies operator for this and additionally adding const assertion would be great:

const fixtures = {
   eth_mainnet: &#39;some value&#39;,
   eth_testnet: &#39;some value 2&#39;,
} as const satisfies Record&lt;supportedChains, string&gt;

The benefit of this approach is that it prevents the compiler from widening the type of the fixtures. With regular type definition the type of fixtures will be: Record&lt;supportedChains, string, however with the satisfies and const assertion it will take the exact values from the object:

{
   eth_mainnet: &#39;some value&#39;,
   eth_testnet: &#39;some value 2&#39;,
}

答案2

得分: 1

设置类型明确,您的对象将受到不希望的属性的保护。当使用 as 关键字时,您只是告诉编译器将对象视为与编译器推断的类型不同的东西。这被称为类型断言

现在您想要使用的是映射类型。顾名思义,这会将您的联合值映射为对象属性键。此外,您可以添加一个 ? 使属性变成可选的。(=> 如果不是所有联合值都是属性,对象仍然有效)

type SupportedChains = "eth_mainnet" | "eth_testnet";

const fixtures: {[Chain in SupportedChains]?: any} = {
  eth_testnet: {},
  eth_mainnet: {},
  extra_prop: {}
  //~~~~~~~~~~ -&gt; 类型 '{ eth_testnet: {}; eth_mainnet: {}; extra_prop: {}; }' 不能分配给...
};
英文:

Set the type explicitly and your object will be guarded against unwanted props. When using the as keyword you only tell the compiler to treat the object as something different than the type the compiler infers the object to be. This is called Type Assertion.

Now what you want to use is a Mapped Type. As the name implies this maps your union values as object property keys. Additionally you could add a ? to make the properties optional. (=> object is still valid if not all union values are there as properties)

type SupportedChains = &quot;eth_mainnet&quot; | &quot;eth_testnet&quot;;

const fixtures: {[Chain in SupportedChains]?: any} = {
  eth_testnet: {},
  eth_mainnet: {},
  extra_prop: {}
//~~~~~~~~~~ -&gt; Type &#39;{ eth_testnet: {}; eth_mainnet: {}; extra_prop: {}; }&#39; is not assignable to...
};

huangapple
  • 本文由 发表于 2023年6月27日 20:58:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76565115.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定