OmitIndexSignature
Omit any index signatures from the given object type, leaving only explicitly defined properties.
This is the counterpart of PickIndexSignature.
Use-cases: - Remove overly permissive signatures from third-party types.
This type was taken from this StackOverflow answer.
It relies on the fact that an empty object ({}) is assignable to an object with just an index signature, like Record<string, unknown>, but not to an object with explicitly defined keys, like Record<'foo' | 'bar', unknown>.
(The actual value type, unknown, is irrelevant and could be any type. Only the key type matters.)
`const indexed: Record<string, unknown> = {}; // Allowed
// @ts-expect-error const keyed: Record<'foo', unknown> = {}; // Error // TS2739: Type '{}' is missing the following properties from type 'Record<"foo" | "bar", unknown>': foo, bar ` Instead of causing a type error like the above, you can also use a conditional type to test whether a type is assignable to another:
type Indexed = {} extends Record<string, unknown> ? '✅ {}is assignable toRecord<string, unknown>' : '❌ {}is NOT assignable toRecord<string, unknown>`';
type IndexedResult = Indexed;
//=> '✅ {} is assignable to Record<string, unknown>'
type Keyed = {} extends Record<'foo' | 'bar', unknown>
? '✅ {} is assignable to Record<\'foo\' | \'bar\', unknown>'
: '❌ {} is NOT assignable to Record<\'foo\' | \'bar\', unknown>';
type KeyedResult = Keyed;
//=> '❌ {} is NOT assignable to Record<\'foo\' | \'bar\', unknown>'
Using a [mapped type](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#further-exploration), you can then check for eachKeyTypeofObjectType`...
type OmitIndexSignature<ObjectType> = { [KeyType in keyof ObjectType // Map each key of ObjectType... ]: ObjectType[KeyType]; // ...to its original value, i.e. OmitIndexSignature == Foo. };
...whether an empty object ({}) would be assignable to an object with that KeyType (Record<KeyType, unknown>)...
type OmitIndexSignature<ObjectType> = { [KeyType in keyof ObjectType // Is {}assignable toRecord<KeyType, unknown>? as {} extends Record<KeyType, unknown> ? never // ✅ {}is assignable toRecord<KeyType, unknown> : KeyType // ❌{}is NOT assignable toRecord<KeyType, unknown> ]: ObjectType[KeyType]; };
If {} is assignable, it means that KeyType is an index signature and we want to remove it. If it is not assignable, KeyType is a "real" key and we want to keep it.
See also:PickIndexSignature Object
ObjectType
ObjectType