I'm struggling with using object spread in Typescript functions that involve Type variables.
Is it currently achievable at all? If not, what are some succinct alternatives?
My findings with both Typescript v2.6 and v2.7-dev are as follows:
In the provided function definitions, those labeled as ok
compile without issues, while the ones marked as err
result in the following compiler error:
Error TS2698: Spread types may only be created from object types.
interface IMessages {
[msgKey: string]: string;
}
const ok1 = () => {
type TFieldNames = "a" | "b" | "c";
const fieldErrors: { [field in TFieldNames]?: IMessages } = {};
const fieldName = "XXX" as TFieldNames;
const otherMessages = fieldErrors[fieldName]; // has type IMessages
fieldErrors[fieldName] = { ...otherMessages, too_big: "is too big" };
};
const ok2 = () => {
type TFieldNames = keyof { a: number; b: number; c: number };
const fieldErrors: { [field in TFieldNames]?: IMessages } = {};
const fieldName = "XXX" as TFieldNames;
const otherMessages = fieldErrors[fieldName]; // has type IMessages
fieldErrors[fieldName] = { ...otherMessages, too_big: "is too big" };
};
const ok3 = () => {
type TFieldNames = string;
const fieldErrors: { [field in TFieldNames]?: IMessages } = {};
const fieldName = "XXX" as TFieldNames;
const otherMessages = fieldErrors[fieldName]; // has type "any"
fieldErrors[fieldName] = { ...otherMessages, too_big: "is too big" };
};
const err1 = <TFieldNames extends string>() => {
const fieldErrors: { [field in TFieldNames]?: IMessages } = {};
const fieldName = "XXX" as TFieldNames;
const otherMessages = fieldErrors[fieldName]; // has type "any"
fieldErrors[fieldName] = { ...otherMessages, too_big: "is too big" };
};
const err2 = <TFields extends { [key: string]: any }>() => {
const fieldErrors: { [field in keyof TFields]?: IMessages } = {};
const fieldName = "XXX" as keyof TFields;
const otherMessages = fieldErrors[fieldName]; // has type "any"
fieldErrors[fieldName] = { ...otherMessages, too_big: "is too big" };
};
const err3 = <TFields extends object>() => {
const fieldErrors: { [field in keyof TFields]?: IMessages } = {};
const fieldName = "XXX" as keyof TFields;
const otherMessages = fieldErrors[fieldName]; // has type "any"
fieldErrors[fieldName] = { ...otherMessages, too_big: "is too big" };
};