I first generate suggestion keys with object keys that can be used like this
const data = {
content: {
value: "string",
},
anotherContent: {
anotherValue: 20
}
}.
const result = function(["content.value","anotherContent.anotherValue"])
First, I wanted the result
type to be {value: number, otherValue: number}
.
So, I type it like this.
<Target, Suggestion extends DotedKeysType<S>[]>(
target?: Target extends Suggestion ? Target : Suggestion
): {
[key in Target extends Suggestion ? Target[number] : string]: Target extends Suggestion
? OutputByKeys<S, key>
: never;
};
Everything works fine, except for the following.
content
, I can use it as follows<View>{result.content}</View>
anotherContent.anotherValue
, I have to use it like this.<View>{result["anotherContent.anotherValue"]}</View>
I also realize that even if we made it, we will have a key problem
// for a data like this. Both last keys are named 'value'
const data = {content: {value: 10},anotherContent: {value: 20}}
// Keeping the result as an object override the value key in the object.
// Since objects can not have same key as property
const result = function(["content.value","anotherContent.value"]);
result = {value : 20 // `Override value of content with anotherContent`}
But with array as an result, Each item in the array can have different name. For example
result = [myFirstValue, mySecondValue] = function(["content.value","anotherContent.anotherValue"])
With that the type of myFirstValue
must be the type of content.value
and the type mySecondValue
must be the type of anotherContent.anotherValue
.
So far, that's how close I've come.
<Target, Suggestion extends DotedKeysType<S>[]>(
target?: Target extends Suggestion ? Target : Suggestion
): OutputByKeys<S, Target extends Sug ? Target[number] : keyof S>[];
This gives me a union type of all the keys in the target array.
result = [value1: string | number, value2: string | number]
Is there a way to get a type like this in case of array?
// type of `content.value` is `string`
// type of `notherContent.anotherValue` is `number`
const result = function(["content.value","anotherContent.anotherValue"]);
result => [myFirstValue, mySecondValue]
result type will be [value1: string, value2: number]
And in case of object where last key are different
// type of `content.value` is `string`
// type of `anotherContent.anotherValue` is `number`
const result = function(["content.value","anotherContent.anotherValue"])
result => {value: "string", anotherValue: 20}
result type => {value: string, anotherValue: number}
I do not want an intersection if possible
// i don't want that if possible
result type => [string & number, string & number]
But i want this
result type => [string, number]
I can't predict the user's choice, otherwise I'd just set the array type => [string, number]
and my problem would be solved. I've read a lot of answers but I still haven't found the one I need.
I ask for the same thing in different ways. For an object because it might be useful in another project and for array because it's my current need.
Hope this can help you. result here
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
type GetProperty<T, S> = S extends `${infer K}.${infer R}`
? K extends keyof T
? GetProperty<T[K], R>
: any
: S extends keyof T
? T[S]
: any;
type GetPropertyFromArray<T, A> = Mutable<A> extends [infer K, ...infer R] ? [GetProperty<T, K>, ...GetPropertyFromArray<T, R>] : A;
function fn<T extends {}, A extends {}>(keys: A): GetPropertyFromArray<T, A> {
return 0 as any;
}
const data = {
content: {
value: 'string',
},
anotherContent: {
anotherValue: 20,
},
};
const keys = ['content.value', 'anotherContent.anotherValue'] as const;
const res = fn<typeof data, typeof keys>(keys);