Given:
interface Customer {
name: string
address: string
phone: string
}
type PartialRecord<K extends keyof any, T> = {
[P in K]?: T
}
// For this, I want the keys to be only fields that are in customer, but I need the derived type to be the fields
// that are actually defined here - not the full set of those in customer
const editableFields: PartialRecord<keyof Customer, string> = {
name: 'The customer name',
} as const;
type EditableCustomer = Pick<Customer, keyof typeof editableFields>
// This gives an error - missing address and phone
const x: EditableCustomer = {
name: 'Bob'
}
The idea is I want to have a function foo(c: EdiableCustomer) that has access just to the fields that are actually editable, based on what labels are defined in editableFields, but I want to maintain the type restriction in the definition of editableFields to only be the keys of Customer, but still have the resulting type be just the union of what is actually defined, and not the entirety of Customer.
The real usage is a bit more complicated than this, but this is my best shot at distilling the problem down into a minimal case. I feel like there is a template solution to this to define editableFields as some type that is inheritable from the PartialRecord, but my template-fu is not great in TS.
Any ideas?
>Solution :
Seems like a perfect case for the satisfies operator:
const editableFields = {
name: 'The customer name',
} satisfies PartialRecord<keyof Customer, string>;
The satisfies keyword tells typescript that it should infer editableFields‘s type based on the actual values written (in this case, that type is { name: string; }), but if the resulting type isn’t compatible with PartialRecord<keyof Customer, string>; you want an error to be shown.