You can achieve that with type intersection:
interface MandatoryProps {
numberProp: number;
boolProp: boolean;
}
type TypeWithMandatoryAndOptionalProps =
// For mandatory props:
MandatoryProps &
// For optionals:
Record<string, string>;
declare const foo: TypeWithMandatoryAndOptionalProps;
foo.blablabla; // string
foo.numberProp; // number
foo.boolProp; // boolean
UPD. I think I've rushed a bit with the answer. Whereas suggested type seems to solve the issue with defining such a type, there's still a bunch of issues with using it (explained by TS maintainers in the issue linked in comments below). You can try to solve the issue with assigning a value to a variable with such a type by casting through any or using Object.assign:
const foo = <TypeWithMandatoryAndOptionalProps><any>{/* ... */};
// or
const bar: TypeWithMandatoryAndOptionalProps = Object.assign(
{ numberProp: 1, boolProp: false },
{ blablabla: 'test' }
);
But both of those options basically tricks type checker rather than providing a sound type system for your program.
TL;DR of that would be as follows. Unless you're trying to get type working an existing JS program, just rethink your types. Use separate property for object with key signature or a Map.
Thanks @jcalz for pointing to TS issue.