In TypeScript, object types are considered "open" or "extendible" rather than "closed" or "exact". This means that while an object type must have known properties, it is not restricted from having additional, unknown properties. Open and extendible object types allow for interface and class extension to create type hierarchies. For example, defining
interface Bar extends Foo { extraProp: string }
signifies that every
Bar
is also a
Foo
, even though
Foo
does not define anything related to
extraProp
. However, this concept may have unexpected implications for developers. Currently, exact types are not fully supported, although excess property checking can sometimes give the illusion of such support. Refer to
microsoft/TypeScript#12936 for more information.
Analyzed by the compiler, the type of obj
is:
/* const obj: {
A: number;
B: number;
C: number;
} */
This indicates that the compiler recognizes numeric properties at keys A
, B
, and C
in obj
. As object types are open, the compiler is unaware of the absence of other properties in obj
. Even though the object literal assigned to obj
lacks additional properties, the type system does not retain this information. Hence, according to the compiler, obj
could potentially have various other properties besides A
, B
, and C
. While accessing these defined properties would not trigger warnings with strict settings, attempting to access an unknown property using a string key may result in the compiler considering it as any
.
To specify the types of unknown properties in TypeScript, one option is to use an index signature like
{[k: string]: number | undefined}
. It is not possible to declare "
A
,
B
, and
C
are of type
number
and all other properties are
undefined
" due to the absence of a suitable index signature mechanism for representing "all other properties". Alternatively, you could state "
A
,
B
, and
C
are
number
and all properties are
number | undefined
". If tracking
A
,
B
, and
C
is unimportant, utilizing the annotation "all properties are
string | undefined
" achieves similar results.
const obj: {[k: string]: number | undefined} = {
"A": 1,
"B": 2,
"C": 3
};
const f = (str: string) => {
const result = obj[str]; // number | undefined
}
The function now explicitly returns number | undefined
based on the specified type.
Playground link showcasing the code