When utilizing a generic type with default arguments, an issue arises where the inference benefit is lost if the variable is declared with the generic type.
Consider the following types:
type Attributes = Record<string, any>;
type Model<TAttributes extends Attributes = Attributes> = {
attributes: TAttributes;
};
function create<TModels extends Record<string, Model>>(
schemas: TModels
): TModels {
return schemas;
}
If objects are typed using Model
and then passed into the generic function, the inference benefit is lost compared to not typing the object. The expected behavior occurs when the generics argument is passed into the Model
type, as demonstrated below:
const TodoWithGeneric: Model<{ name: string; finished: string }> = {
attributes: {
name: "string",
finished: "boolean"
}
};
const TodoWithoutGeneric: Model = {
attributes: {
name: "string",
finished: "boolean"
}
};
const withInference = create({
Todo: { attributes: { name: "string", finished: "boolean" } }
});
const withGenericsPassed = create({ Todo: TodoWithGeneric });
const withoutAttributesPassedToGeneric = create({
Todo: TodoWithoutGeneric
});
Is there a workaround in TypeScript to retain the benefits of typing the object declaration without needing to pass in generic arguments, while still allowing inference once it's passed into a function?
It would be ideal to have TypeScript support on the declaration for TodoWithoutGeneric
, but by the time it is passed into withoutAttributesPassedToGeneric
, we want to remove the Model
type and allow inference to take over.
The combined code snippets mentioned above can be found in this sandbox: Code Sandbox here
The withInference.Todo.attributes.
and
withGenericsPassed.Todo.attributes.
provide access to attribute keys, whereas the withoutAttributesPassedToGeneric.Todo.attributes
(typed with generic) does not.
Thank you!