Reputation: 3705
Consider the next example:
enum Keys {
A = 'a',
B = 'b',
C = 'c',
}
//imagine a lot more possible keys
type ExtendKeysPropsByKey = {
[Keys.A]: {
a: string
}
[Keys.B]: {
b: string
}
}
//Keys.C doesn't require extended props
type KeysPropsByKey = {
[key in keyof Keys]: {
key: key
} & ExtendKeysPropsByKey[key]
//errors: Type 'key' cannot be used to index type 'ExtendKeysPropsByKey'.
//also tried:
//ExtendKeysPropsByKey[key] ? ExtendKeysPropsByKey[key] : {}
//ExtendKeysPropsByKey[key] || {}
//key in keyof ExtendKeysPropsByKey ? ExtendKeysPropsByKey[key] : {}
//neither works
}
So imagine that there's 50 possible Keys
, and we want to create a type which initially contains a key
prop with the actual value of Keys
, and would like to be able to optionally extend the props, so the expected type for the above example would be:
{
[Keys.A]: {
key: Keys.A
a: string
}
[Keys.B]: {
key: Keys.B
b: string
}
[Keys.C]: {
key: Keys.C
}
}
Any possible scenarios?
Upvotes: 0
Views: 145
Reputation: 20162
I hope I get what you ask for :). So I made a type constructor with two parameters - Keys
- it defines what keys we will have, KeyProps
- type represents what props given key should have.
enum Keys {
A = 'a',
B = 'b',
C = 'c',
}
type ExtendKeysPropsByKey = {
[Keys.A]: {
a: string
}
[Keys.B]: {
b: string,
c: number;
}
}
type MakeT<Keys extends string, KeyProps extends Partial<Record<Keys, any>>> = {
[K in Keys]: {key: K} & (K extends keyof KeyProps ? KeyProps[K] : {})
}
type Result = MakeT<Keys, ExtendKeysPropsByKey>
/**
type Result = {
a: {
key: Keys.A;
} & {
a: string;
};
b: {
key: Keys.B;
} & {
b: string;
c: number;
};
c: {
key: Keys.C;
};
}
*/
Explanation:
KeyProps extends Partial<Record<Keys, any>>
we define second argument as record with keys we want but also it is partial, as not all keys we require.{key: K} & (K extends keyof KeyProps ? KeyProps[K] : {})
we say our value at given key will have property key
equal our key, and we intersect it with props given in KeyProps
objectUpvotes: 2