When TypeScript's structural type system considers {a: number, c: string}
to be assignable to {a: number}
, it may seem confusing that the compiler complains when passing
{a: 2, c: "type-error"}
to a function expecting a value of type
A
.
The reason for this is known as excess property checking. When an object literal with more properties than expected is used in a context where a simpler type is anticipated, the compiler warns because it assumes you might be discarding important information:
If the acceptA
function only expects objects of type
A</code, additional properties like <code>c
become inaccessible within
acceptA
. Thus, passing such object literals leads to potential loss of data. The extra property becomes redundant both inside and outside the scope of
acceptA</code.</p>
<p>To avoid this warning, one approach is to save the object literal into a variable first, permitting access to all its properties:</p>
<pre><code>const obj = { a: 2, c: "okay" }
// const obj: {a: number, c: string}
acceptA(obj); // No issue now
Before attempting workarounds, ensure excess property checking does not serve a purpose in your specific scenario. If desired, modifications can be made to allow for object literals with surplus properties without triggering warnings.
One solution involves explicitly defining that acceptA
accepts values conforming to type A
alongside a more general "anything-goes" object type like {[k: string]: any}
:
function acceptA(a: A & { [k: string]: any }) {
a.c // any
return a
}
acceptA({ a: 2, c: "okay" })
By doing so, all property keys are expected, eliminating the concept of excess properties. Although not completely foolproof, this method reduces the likelihood of losing type-specific information.
Alternatively, making use of generics in the type definition for the argument passed to acceptA
can also address the excess property check concerns:
function acceptA<T extends A>(a: T) {
return a
}
acceptA({ a: 2, c: "okay" })
This implementation allows the compiler to maintain awareness of the specific type being utilized, reducing the risk of sacrificing valuable type details. While neither approach guarantees preservation of type information, they offer ways to navigate around excess property checks.
Note that excess property checking is just one of many precautions enforced by the TypeScript compiler, aimed at promoting code consistency and minimizing errors. Understanding these checks and their implications is essential for writing robust and reliable TypeScript applications.
Click here to view the code on TypeScript playground