Here is the code with some comments about what I would like to do and where I have an issue (more details about the issue after the code block):
type AttributeDefinition = {
name:string
}
type EntityDefinition = {
name: string
attributes: Readonly<AttributeDefinition[]>
}
type EntityDefinitionSource = Partial<EntityDefinition>
type Entity<ET extends EntityDefinition> = {
[K in ET['attributes'][number] as K['name']]: any
}
/////////////////////////////////////////
// this function returns the given object, and is only used to constraint the object type
// this is what I had previously, but now that I want to add missing properties on returned object I have an issue - look at makeDefinitionFromSource()
function makeDefinition<D extends EntityDefinition>(definition:D): D{
return definition
}
const def1 = makeDefinition({
name: 'myEntityDefinition',
attributes: [
{name:'foo'}
] as const
})
const entity1a: Entity<typeof def1> = {
foo: 42, // here typescript accept the "foo" key, which is the expected behavior
}
const entity1b: Entity<typeof def1> = {
baz: 42, //here typescript refuse to use "baz" as a key, which is the expected behavior
}
/////////////////////////////////////////
// this function return a new object using the given source object, but the "as const" constraint from source is not preserved on returned object
function makeDefinitionFromSource<D extends EntityDefinitionSource>(definition:D): EntityDefinition{
return {
name: definition.name || 'defaultName',
attributes: definition.attributes
//attributes: definition.attributes as const
// ↳ one attempt was to add the constraint here, but it throws an error
// TS1355: A 'const' assertions can only be applied to references to enum members, or string, number, boolean, array, or object literals
}
}
const def2 = makeDefinitionFromSource({
attributes: [
{name:'foo'}
] as const
})
const entity2a: Entity<typeof def2> = {
foo: 42, // here typescript accept the "foo" key, which is the expected behavior (but it does because of a lack of typing)
}
const entity2b: Entity<typeof def2> = {
baz: 42, // so here typescript does not reject he "baz" key, which is not the expected behavior (it accept any key)
}
As mentioned in the comments, I would like to use an object (an EntityDefinitionSource) to build another one (an EntityDefinition) using a function that would set default values to missing properties.
Is there a way to preserve such a constraint, or to add it (I would even prefer this approach) when the returned object is built (look at my commented attempt in makeDefinitionFromSource)?