Reputation: 30097
I have a main interface in my project which dictates the value
type of the properties of the extending objects.
For the sake of simplicity, let's assume it is like this:
interface Printable extends Record<PropertyKey, string> {
}
It just says all the value
s should be string
. And it properly prohibits its extending interfaces to have a number
key, like below.
interface Receipt extends Printable {
customerName: string;
// customerId: number; // EXPECTED: This line errors if uncommented (Property 'customerId' of type 'number' is not assignable to string index type 'string'. (2411))
}
However, the unwanted side-effect is that it widens the "key" range to be "any string
", so it doesn't catch the following error:
const r: Receipt = { customerName: "Jack" };
console.log(r.address); // UNEXPECTED: This line DOESN'T error "for Property 'address' does not exist on type 'Receipt'.(2339)"
How can I get the "enforced value type" benefit from a super-interface, without the unwanted "widened key range"?
PS. It's different from TypeScript: Create typed Record without explicitly defining the keys in the sense that here I want an interface with no overhead on the objects or their instantiation. Please stop reporting it as a duplicate. :)
Upvotes: 2
Views: 1821
Reputation: 37996
You can create utility type based on generic type constraint to validate input type values:
type Printable<T extends Record<PropertyKey, string>> = T;
type Receipt = Printable<{
customerName: string;
// customerId: number; // Expect error
}>
const r: Receipt = { customerName: "Jack" };
console.log(r.address); // Property 'address' does not exist on type '{ customerName: string; }'.
Upvotes: 3
Reputation: 3253
I don't think it's possible at least now, because you have to do something like this:
interface Printable extends Record<keyof Printable, string> {
}
Which gives an error regarding the recursive use of Printable interface
and doesn't make much sense tbh. the only solution that comes to my mind, is like below.
type StringOnly<T extends string> = Record<T, string>
type Printable = StringOnly<"key1" | "key2" | "key3">
interface Receipt extends Printable {
customerName: string;
}
const r: Receipt = { customerName: "Jack"};
console.log(r.address); // Property 'address' does not exist on type 'Receipt'.(2339)
Upvotes: 0