Is it possible to construct some type directly from the string provided?
I want to create a type something like shown below:
type MyConfiguration<T> = {
items: T[];
onChange: (updated: ConstructedType<T>) => void;
}
const conf: MyConfiguration = {
items: ['id', 'nested.id', 'nested.name'],
onChange: updated => {
console.log(`You updated ${updated.nested.name}(id: ${updated.nested.id})`);
},
};
So it will generate a type for updated
to be {id: string; nested: { id: string; name: string}}
CodePudding user response:
This solution might not be perfect but the type of updated
seems to be correct:
type First<T extends string> = T extends `${infer L}.${string}` ? L : T
type Nested<T extends string> = T extends `${string}.${infer R}` ? R : string
type _ConstructedType<T extends string> = string extends Nested<T> ? string : {
[Key in T as First<Nested<T>>]: _ConstructedType<Nested<T>>
}
type ConstructedType<K extends readonly string[]> = {
[Key in K[number] as First<Key>]: _ConstructedType<Key>
}
function createConf<K extends readonly string[]>(conf: {items: K, onChange: (updated: ConstructedType<K>) => any}) {
return conf
}
createConf({
items: ['id', 'nested.id', 'nested.name'] as const,
onChange: updated => {
console.log(`You updated ${updated.nested.name}(id: ${updated.nested.id})`);
},
})
In your question you specified that you want to have a type
called MyConfiguration
. A type
alone cannot enforce any constraints between properties. So we have to create a factory function called createConf
. We can now pass a conf
object to createConf
and all types are inferred.
A drawback that I don't know how to fix yet, is that you have to write as const
behind the items
array. Otherwise TypeScript will infer the type as string[]
and not as a tuple.