英文:
With Typescript, can I get the type of a value in an object in an array, based on the value of another key in the same object?
问题
以下是翻译的代码部分:
我有以下对象:
const features = [{
key: 'some-key',
fallback: true
}, {
key: 'another-key',
fallback: 'a string'
}] as const;
如你所见,fallback 值可以是不同的类型。
现在,我想要一个函数从 API 中检索特征的值。如果没有,它应该返回 fallback。
但我想要在某些情况下有可能用自己的值覆盖 fallback。然后我需要 fallback 的类型,与 'selected' 键相关。
现在,我以这种方式获取可能的键列表:
type FeatureKey = typeof features[number]['key'];
然后我创建一个函数:
function getFeature(key: FeatureKey) {
// 一些 API 调用,否则返回 fallback
return features.find(feature => feature.key === key)?.fallback;
}
但我想要添加一个参数来覆盖那一刻的 fallback:
function getFeature(key: FeatureKey, fallback: [基于给定键的 FALLBACK 的类型]) {
// 一些 API 调用,否则返回 fallback
return features.find(feature => feature.key === key)?.fallback;
}
我的问题是:是否可以根据函数中给定的键名获取 fallback 值的类型?
因此,当我使用 `getFeature('some-key', [...])` 时,我必须提供一个布尔值作为 fallback 参数。当我使用 `getFeature('another-key', [...])` 时,我必须提供一个字符串作为 fallback。
英文:
I got the following object:
const features = [{
key: 'some-key',
fallback: true
}, {
key: 'another-key',
fallback: 'a string'
}] as const;
As you can see, the fallback value can be different types.
Now I want a function to retrieve the value of a feature from an API. If there is none, it should return the fallback.
But I want the possibility to overwrite the fallback at some cases with my own. Then I need the type of the fallback, related to the 'selected' key.
Now, I get the list of possible keys in this way:
type FeatureKey = typeof features[number]['key'];
Then I create a function:
function getFeature(key: FeatureKey) {
// Some API Call, but otherwise return fallback
return features.find(feature => feature.key === key)?.fallback;
}
But I want to add an argument to overwrite the fallback for that moment:
function getFeature(key: FeatureKey, fallback: [TYPEOF FALLBACK BASED ON GIVEN KEY]) {
// Some API Call, but otherwise return fallback
return features.find(feature => feature.key === key)?.fallback;
}
My question is: is it possible to get the type of the fallback value, based on the given key name in the function?
So when I use getFeature('some-key', [...])
, I have to give in a boolean als fallback argument. And when I use getFeature('another-key', [...])
, I have to give in a string as fallback.
答案1
得分: 2
首先,您需要定义它们的关系:
```ts
type FeatureMap = {
[K in typeof features[number] as K["key"]]: K["fallback"]
}
type FeatureKey = keyof FeatureMap;
并使用泛型声明函数:
function getFeature<T extends FeatureKey>(key: T, fallback: FeatureMap[T])
请注意,fallback
参数的类型将与原始对象相同
例如:当
key
为some-key
时,fallback
将为true
而不是boolean
如果需要使 fallback
的类型更“宽泛”,我建议以相反的方式定义这些类型。首先创建 FeatureMap
,然后使用它来创建 features
对象(如果其他地方仍然需要它):
interface FeatureMap {
"some-key": boolean
"another-key": string
}
type Feature<T extends FeatureKey = FeatureKey> = T extends T ? {
key: T,
fallback: FeatureMap[T]
} : never
const features: Feature[] = [{
key: 'some-key',
fallback: true
}, {
key: 'another-key',
fallback: 'a string'
}]
这里是关于 T extends T
的一些解释,供参考:https://stackoverflow.com/questions/69167148/why-ts-toolbelt-library-use-o-extends-unknown-expression
<details>
<summary>英文:</summary>
You will need to define their relationship first:
```ts
type FeatureMap = {
[K in typeof features[number] as K["key"]]:K["fallback"]
}
type FeatureKey = keyof FeatureMap;
and declare the function with generic:
function getFeature<T extends FeatureKey>(key: T, fallback: FeatureMap[T])
note that the type of fallback
parameter will be the same to the original object
> for example: when the key
is some-key
, fallback
will be true
instead of boolean
If the type of fallback
need to be more "widen", I will suggest to
defined these types reversely. Create the FeatureMap
first, then use it to create features
object (if it still needed for other places):
interface FeatureMap {
"some-key": boolean
"another-key": string
}
type Feature<T extends FeatureKey = FeatureKey> = T extends T ? {
key: T,
fallback: FeatureMap[T]
} : never
const features: Feature[] = [{
key: 'some-key',
fallback: true
}, {
key: 'another-key',
fallback: 'a string'
}]
and here is some explains about T extends T
just FYI: https://stackoverflow.com/questions/69167148/why-ts-toolbelt-library-use-o-extends-unknown-expression
答案2
得分: 1
你需要先扩展 features
中的字面类型:
// 以后可以添加更多类型
type Widen<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
然后根据给定的键扩展回退类型:
function getFeature<K extends FeatureKeys>(key: K, fallback?: Widen<Extract<typeof features[number], { key: K }>["fallback"]>) {
return features.find(feature => feature.key === key)?.fallback ?? fallback;
}
你也可以使用映射类型(类似 Jerry 的答案)来简化:
function getFeature<K extends FeatureKeys>(key: K, fallback?: Widen<FeatureMap[K]>) {
return features.find((feature) => feature.key === key)?.fallback ?? fallback;
}
英文:
You need to widen the literal type in features
first:
// you can tack on more types later
type Widen<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
then widen the fallback type based on the given key:
function getFeature<K extends FeatureKeys>(key: K, fallback?: Widen<Extract<typeof features[number], { key: K }>["fallback"]>) {
return features.find(feature => feature.key === key)?.fallback ?? fallback;
}
You can also use a mapped type (like Jerry's answer) to simplify:
function getFeature<K extends FeatureKeys>(key: K, fallback?: Widen<FeatureMap[K]>) {
return features.find((feature) => feature.key === key)?.fallback ?? fallback;
}
答案3
得分: 0
以上的答案将解决我的问题,但目前我选择了一个更简单的解决方案。而不是创建一个名为getFeature
的函数来获取布尔值和/或字符串,我将创建两个特定于类型的函数。
因此,我将创建一个getFeatureToggle
函数和一个getFeatureValue
函数。然后我将始终知道我应该使用布尔值或字符串。
对于其他程序员来说,也许更容易理解要使用哪个函数以及它的作用。
英文:
The answers above will fix my problem, but for now I've chosen for a more simple solution. Instead of creating one function getFeature
to get booleans and / or strings, I will make two functions, specific for the type.
So I will create a getFeatureToggle
function and a getFeatureValue
. Then I will always know I have to use a boolean or a string.
Also for other programmers it's maybe better to understand which function to use and wat it does.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论