Due to TypeScript's structural typing system, the error concerning badKey
is suppressed. In this system, compatibility between types is determined based on one type containing all the fields of another type. For more specific information, refer to the type compatibility section in the TypeScript documentation.
To simplify, let's name the interfaces as HasFoo
and HasFooAndBadKey
.
interface HasFoo {
foo: string;
}
interface HasFooAndBadKey {
foo: string;
badKey: string;
}
The interface HasFooAndBadKey
includes the field foo
, making it compatible with type HasFoo
. Hence, the code below is valid and compiles successfully:
const withBadKey: HasFooAndBadKey = {
foo: "bar",
badKey: "baz"
};
const item: HasFoo = withBadKey;
However, attempting the same assignment using a literal will result in an error stating
Object literal may only specify known properties, and 'badKey' does not exist in type 'HasFoo'.
const other: HasFoo = {
foo: "bar",
badKey: "baz" // Error
}
Therefore, the issue is not related to generics but to specifying known properties in literals. The generic passthrough function does not trigger a compile-time error because it returns a value that is type-compatible with HasFoo
. Explicitly typing passthrough to expect a HasFoo
and passing the same literal containing badKey
will yield the same error.
interface HasFoo {
foo: string;
}
interface HasFooAndBadKey {
foo: string;
badKey: string;
}
function expectInterface(args: HasFoo): void {}
function passthrough<T>(fields: T): T {
return fields
}
// Expecting a literal HasFoo which can only contain a foo field
expectInterface({
foo: 'bar',
badKey: 'baz', // error
})
const item: HasFooAndBadKey = {
foo: 'bar',
badKey: 'baz'
};
expectInterface(item); // No error
// Non-literal value returned by passthrough. The non-literal
// is type compatible with HasFoo, so no error occurs.
expectInterface(passthrough<HasFooAndBadKey>({
foo: 'bar',
badKey: 'baz', // no error
}))
// Now, passthrough displays an error because we instructed it to expect a HasFoo,
// and this HasFoo literal cannot include any keys other than 'foo'.
expectInterface(passthrough<HasFoo>({
foo: 'bar',
badKey: 'baz', // error
}))